admin管理员组

文章数量:1641792

关于命令行参数解析的库还挺多,调研之后选择了 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,也需要打印版本号然后退出。

更多强大功能,请参考文档。

本文标签: 命令行参数快速picocli