[这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战]
一、实例
由于业务要求,需要提供一个cli命令行的工具。由于本人接触java比较多,于是采用了java以及picocli进行开发。从没接触过picocli,简单的记录一下相关的知识点。
开发环境
选择picocli有以下几个好处:
- 支持注解,可以快速开发;
- 支持打包成jar包;也支持通过
Grallvm的native-image插件进行编译,不需要再依赖JDK就能够运行
开发环境:
- 系统
- win10
- JDK选择
- jdk8
- graalvm
- 第三方相关框架
- okhttp
- picocli-4.6.1
在记录这些资料的时候,picocli更新到4.6.1,所以引入对应版本的jar包即可。
相关maven配置
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.6.1</version>
</dependency>
示例
如下所示,定义了两个类CosimCommand以及CheckCommand,程序的执行入口是CosimCommand的main方法。
在CosimCommand上标记了注解@CommandLine.Command用于告诉程序这是一个命令,相关属性如下:
- name 命令名称
- mixinStandardHelpOptions 是否支持
-h等帮助命令 - version 表示命令的版本
- description
- subcommands 表示子命令
相关源码:
//主命令
@CommandLine.Command(
name = "cosim",
mixinStandardHelpOptions=true,
version = "1.0-SNAPSHOT",
description = "cosim",
subcommands = {
CheckCommand.class
}
)
public class CosimCommand implements Runnable{
public static void main(String[] args) {
int exitCode = new CommandLine(new CosimCommand()).execute(args);
System.exit(exitCode);
}
@Override
public void run() {
System.out.println("The popular git command");
}
}
//子命令
@CommandLine.Command(
name = "check",
mixinStandardHelpOptions=true,
description = "子命令示例"
)
public class CheckCommand implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("test");
return null;
}
}
执行
程序编写好后,可以通过IDEA执行,也可以通过jar包运行;在maven中添加以下构建配置进行打包:
<build>
<finalName>cosim-cli</finalName>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
// 这个配置用于导出依赖的jar包
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
// 用于定义主类
<mainClass>com.simtek.cosimcloud.cli.CosimCommand</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
- 添加maven配置
- 打包后生成cosim-cli-jar-with-dependencies.jar
- 执行命令:
java -cp .\cosim-cli-jar-with-dependencies.jar com.simtek.cosimcloud.cli.CosimCommand check
注:CosimCommand这个类相当于cosim主命令,check是定义的子命令。
二、选项和参数
相关注解
picocli中常用的注解是@CommandLine.Command、@CommandLine.Option、@CommandLine.Parameters。
@CommandLine.Command 用于定义命令,相关属性
- name 用于定义命令名称
- aliases 用于定义别名,允许多个
- subcommands 用于定义一个或多个子命令
- mixinStandardHelpOptions 启用–help
- description 描述命令
@CommandLine.Option 用于定义命令选项(可选)
- names 用于定义选项的一个或多个名称;Picocli 允许您使用任何您想要的选项名称。默认情况下,选项名称区分大小写,但这是可定制的。
- paramLabel 参数分组
- description 表示命令选项的描述
- usageHelp
- help
- order 选项排序
- required 标记选项是否必需
@CommandLine.Parameters 用于定义命令参数(必选)
- paramLabel 参数分组
- description 表示命令选项的描述
@CommandLine.ArgGroup:Picocli 4.0 引入了一个新的@ArgGroup注释及ArgGroupSpec;可用于定义:
- 互斥选项
- 必须同时出现的选项(从属选项)
- 使用帮助消息中的选项部分
- 重复复合参数
交互式(密码)选项【Interactive (Password) Options】
在 Java 6 或更高版本上运行时,picocli 将使用Console.readPasswordAPI,以便用户输入不会回显到控制台。从 picocli 4.6 开始,应用程序可以选择通过设置将用户输入回显到控制台echo = true,并设置prompt文本以控制在询问用户输入时在控制台上显示的内容。
@CommandLine.Command(
name = "test",
mixinStandardHelpOptions=true,
description = "test"
)
public class TestCommand implements Callable<Integer> {
// 设置属性interactive = true
@CommandLine.Option(names = {"-p", "--password"}, description = "Passphrase", interactive = true)
char[] password;
@Override
public Integer call() throws Exception {
System.out.println(password);
return 1;
}
}
执行后有以下的交互,会提示输入密码:
可选交互参数
默认情况下,交互选项会导致应用程序等待 stdin 上的输入。对于需要以交互方式和批处理模式运行的命令,如果该选项可以选择使用命令行中的参数,则非常有用。
使用arity设置可选:
@Option(names = "--user")
String user; // arity = "0..1" 允许调用命令时接受零到一个参数
@Option(names = "--password", arity = "0..1", interactive = true)
char[] password;
使用以下输入,password字段将被初始化为”123”不提示用户输入:
--password 123 --user Joe
但是,如果未指定密码,则会提示用户输入值。在下面的示例中,密码选项没有参数,因此将提示用户在控制台上输入一个值:
--password --user Joe
短 (POSIX) 选项
Picocli 支持POSIX 的短选项:一个或多个不带选项参数的单字符选项,后面可以跟最多一个带有选项参数的选项,可以分组在一个“-”分隔符后面。
class ClusteredShortOptions {
@Option(names = "-a") boolean aaa;
@Option(names = "-b") boolean bbb;
@Option(names = "-c") boolean ccc;
@Option(names = "-f") String file;
}
<command> -abcfInputFile.txt
<command> -abcf=InputFile.txt
<command> -abc -f=InputFile.txt
<command> -ab -cf=InputFile.txt
<command> -a -b -c -fInputFile.txt
<command> -a -b -c -f InputFile.txt
<command> -a -b -c -f=InputFile.txt
...
布尔选项
布尔选项通常不需要参数:在命令行中指定选项名称就足够了。
class BooleanOptions {
@Option(names = "-x")
boolean x;
}
class BooleanOptionWithParameters {
@Option(names = "-x", arity = "1", description = "1 mandatory parameter")
boolean x;
@Option(names = "-y", arity = "0..1", description = "min 0 and max 1 parameter")
boolean y;
}
注:从 picocli 4.0 开始,布尔选项可以是negatable,即可选的;默认是false。
索引(index)
index属性(从0开始的整数)用于准确指定要捕获的参数;可以使用数组或集合字段捕获多个值。index属性接受范围值,因此像这样的注释会@Parameters(index=”2..4”)捕获索引 2、3 和 4 处的参数。范围值可以是开放式的。例如,@Parameters(index=”3..*”)捕获索引 3 及以上的所有参数。
class PositionalParameters {
@Parameters(index = "0") InetAddress host;
@Parameters(index = "1") int port;
@Parameters(index = "2..*") File[] files;
@Parameters(hidden = true) // "hidden": don't show this parameter in usage help message
List<String> allParameters; // no "index" attribute: captures _all_ arguments
}
省略索引:
- 对于多个位置参数来说,省略
index属性意味着该字段捕获所有位置参数(相当于index = “0..*”); - 对于单个位置参数,从 4.3 版开始,picocli 会根据同一命令中定义的其他位置参数自动分配索引。
注:从 picocli 2.0 开始,可以在命令行的任何位置指定位置参数,它们不再需要遵循选项。任何不是选项或子命令的命令行参数都被解释为位置参数。
双破折号 ( --)
当命令行参数之一是两个没有附加任何字符的破折号 (–) 时,picocli 会将所有后续参数解释为位置参数,甚至是与选项名称匹配的参数。