转载

命令行参数解析picocli快速使用

关于命令行参数解析的库还挺多,调研之后选择了 picocli 这个库 因为其文档很全,所以下面是一个快速使用的教程,抓住主干再揪细节。
 <dependency>
 <groupId>info.picocli</groupId>
 <artifactId>picocli</artifactId>
 <version>4.5.2</version>
 </dependency>

效果

先看看,再实现
$ java -jar cli.jar -h
Usage: java -jar cli.jar [-hV] -p=<secret> -u=<user> [-c=<String=String>]...
 -s=<servers>[,<servers>...] [-s=<servers>[,
 <servers>...]]...
 -c, --config=<String=String>
 -c k1=v1 -c k2=v2
 -h, --help Show this help message and exit.
 -p, --password=<secret> login secret or password
 -s, --server=<servers>[,<servers>...]
 servers,split by comma: host1:port1,host2:
 port2
 -u, --user=<user> login username
 -V, --version Print version information and exit.

定义参数类

使用注解来定义参数类 一般只需要2个注解即可搞定:
  • @CommandLine.Command: 定义在类上,声明应用执行名字,版本等
  • @CommandLine.Option: 用在属性上,代表参数
下面是一个示例:
import picocli.CommandLine;

import java.util.Map;

@CommandLine.Command(name = "java -jar cli.jar")
public class CliParam {

 @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = " cmd cli help msg")
 public boolean help = false;

 @CommandLine.Option(names = {"-s", "--server"}, required = true, split = ",", converter = ServerTypeConverter.class,
 description = " servers,split by comma: host1:port1,host2:port2 ")
 public String[] servers;

 @CommandLine.Option(names = {"-u", "--user"}, required = true, description = "login username")
 public String user;

 @CommandLine.Option(names = {"-p", "--password"}, required = true,
 description = "login secret or password")
 public String secret;

 /**
 * 一些额外的参数
 */
 @CommandLine.Option(names = {"-c", "--config"}, description = " -c k1=v1 -c k2=v2")
 public Map<String, String> configs;

 static class ServerTypeConverter implements CommandLine.ITypeConverter<String> {

 @Override
 public String convert(String s) {
 final String[] hp = s.split(":");
 if (hp.length != 2) {
 throw new CommandLine.TypeConversionException("Invalid servers, must be: host1:port1,host2:port2," +
 " but was:'" + s + "'");
 }
 String host = hp[0].trim();
 int port = Integer.parseInt(hp[1].trim());
 return host + (port == 80 ? "" : ":" + port);
 }
 }
}

其中ServerTypeConverter可以自定义解析,这里接收一个逗号分割的字符串,返回一个数组。

声明版本

可以直接写死,也可以动态加载
@CommandLine.Command(name = "java -jar cli.jar",
 versionProvider = CliParam.MyVersionProvider.class)
public class CliParam {

 /**
 * 动态获取版本号,从内部配置里获取
 */
 static class MyVersionProvider implements CommandLine.IVersionProvider {

 @Override
 public String[] getVersion() throws Exception {
 final InputStream in = MyVersionProvider.class.getClassLoader().getResourceAsStream("config.properties");
 final Properties p = new Properties();
 p.load(in);
 return new String[]{"My APP", "Version " + p.getProperty("version", "unknown")};
 }
 }
}

进阶

我们知道每个命令行都会有 -h和-v这俩选项,所以人家早就考虑好了。 只需要一个选项即可:
@CommandLine.Command(name = "java -jar cli.jar",
 mixinStandardHelpOptions = true,
 versionProvider = CliParam.MyVersionProvider.class)
public class CliParam {}
定义完了,就需要在main方法里解析了。
 public static void main(String[] args) throws Exception {
 // 解析参数
 final CliParam CliParam = new CliParam();
 final CommandLine commandLine = new CommandLine(CliParam);
 try {
 final CommandLine.ParseResult parseResult = commandLine.parseArgs(args);
 if (parseResult.isUsageHelpRequested()) {
 commandLine.usage(System.out);
 System.exit(0);
 }
 if (parseResult.isVersionHelpRequested()) {
 commandLine.printVersionHelp(System.out);
 System.exit(0);
 }
 CliParam.setINSTANCE(CliParam);
 } catch (CommandLine.ParameterException e) {
 commandLine.usage(System.out);
 System.exit(1);
 }

 // 使用 cliParam
当遇到未知参数时,会抛出 CommandLine.ParameterException, 捕获了打印help即可。 正常解析完如果是 -V,也需要打印版本号然后退出。 更多强大功能,请参考文档
正文到此结束
Loading...