Picocli之多级命令行参数解析

11 篇文章 0 订阅

平时用Java写一些小工具,难免用到命令行参数解析,参数比较多的时候,再使用 args 一个个去判断就比较麻烦,且不优雅。
所以,使用现成的Picocli开源组件来实现。

下面记录的代码可以直接拿来用,以后就懒得写了。

0.效果

看看要达到的效果:

我们打包独立运行的 app.jar,使用 java -jar app.jar 参数运行。
我们的工具有多种功能,目前仅展示2个,所以我们不想直接就跟参数,想在中间插一级表示功能的命令:

# 导出
java -jar app.jar export -u xx -d  xx ...
# 导入
java -jar app.jar import -u xx -d  xx ...

完整的参数:

Usage: java -jar app.jar [-hV] [COMMAND]
  -h, --help      Show this help message and exit.
  -V, --version   Print version information and exit.
Commands:
  export
  import
Usage: java -jar app.jar export [-hV] [-d=<database>] -p=<secretKey>
                                -r=<jdbcUrl> [-t=<tables>] -u=<username>
  -d, --database=<database>  库名,默认为default
  -h, --help                 Show this help message and exit.
  -p, --secret-key=<secretKey>
                             秘钥
  -r, --jdbc-url=<jdbcUrl>   数据库地址
  -t, --table=<tables>       表名,多个表用逗号分开
  -u, --username=<username>  用户名
  -V, --version              Print version information and exit.
Usage: java -jar app.jar import [-hV] -f=<from> -p=<secretKey> -r=<jdbcUrl>
                                -t=<to> -u=<username>
  -f, --from=<from>          来源
  -h, --help                 Show this help message and exit.
  -p, --secret-key=<secretKey>
                             秘钥
  -r, --jdbc-url=<jdbcUrl>   数据库地址
  -t, --to=<to>              目标
  -u, --username=<username>  用户名
  -V, --version              Print version information and exit.

1.依赖

        <dependency>
            <groupId>info.picocli</groupId>
            <artifactId>picocli</artifactId>
            <version>4.5.2</version>
        </dependency>

2.实现代码

Picocli可以使用注解的方式代表参数类,我们采用注解。

我们首先定义父命令,使用 subcommands 表示子命令类。

@CommandLine.Command(
        name = "java -jar app.jar",
        subcommands = {ExportCmd.class, ImportCmd.class},
        mixinStandardHelpOptions = true,
        helpCommand = true)
public class CmdParam {
}

子命令类实现,就是最基础的Command注解和Option注解的使用。

    @CommandLine.Command(name = "export", mixinStandardHelpOptions = true, helpCommand = true)
    public class ExportCmd {
        @CommandLine.Option(names = {"-r", "--jdbc-url"}, required = true, description = "数据库地址")
        public String jdbcUrl;
        @CommandLine.Option(names = {"-u", "--username"}, required = true, description = "用户名")
        public String username;
        @CommandLine.Option(names = {"-p", "--secret-key"}, required = true, description = "秘钥")
        public String secretKey;
        @CommandLine.Option(names = {"-d", "--database"}, defaultValue = "default", description = "库名,默认为default")
        public String database;
        @CommandLine.Option(names = {"-t", "--table"}, description = "表名,多个表用逗号分开")
        public String tables;
    }

    @CommandLine.Command(name = "import", mixinStandardHelpOptions = true, helpCommand = true)
    public class ImportCmd {
        @CommandLine.Option(names = {"-r", "--jdbc-url"}, required = true, description = "数据库地址")
        public String jdbcUrl;
        @CommandLine.Option(names = {"-u", "--username"}, required = true, description = "用户名")
        public String username;
        @CommandLine.Option(names = {"-p", "--secret-key"}, required = true, description = "秘钥")
        public String secretKey;
        @CommandLine.Option(names = {"-f", "--from"}, required = true, description = "来源")
        public String from;
        @CommandLine.Option(names = {"-t", "--to"}, required = true, description = "目标")
        public String to;
    }

但是,这还没完,我们再main方法的入口进行解析。

当解析错误、或者参数为空时,我们打印help结果,包括父子命令。

    public static void main(String[] args) {
        // 解析参数
        final CmdParam cmdParam = new CmdParam();
        final CommandLine commandLine = new CommandLine(cmdParam);
        try {
            final CommandLine.ParseResult parseResult = commandLine.parseArgs(args);
            checkParamHelp(args.length == 0, commandLine, parseResult);
            if (parseResult.hasSubcommand()) {
                for (CommandLine.ParseResult subCommand : parseResult.subcommands()) {
                    final CommandLine c = subCommand.commandSpec().commandLine();
                    checkParamHelp(args.length == 1, c, subCommand);
                }
            }
        } catch (CommandLine.ParameterException e) {
            commandLine.usage(System.out);
            for (CommandLine c : commandLine.getSubcommands().values()) {
                c.usage(System.out);
            }
            System.exit(1);
        }
        log.info("cmd params:{}", cmdParam);
    }

    private static void checkParamHelp(boolean empty, CommandLine commandLine, CommandLine.ParseResult parseResult) {
        if (empty || parseResult.isUsageHelpRequested()) {
            commandLine.usage(System.out);
            System.exit(0);
        }
        if (parseResult.isVersionHelpRequested()) {
            commandLine.printVersionHelp(System.out);
            System.exit(0);
        }
    }

最后打包成一个可执行jar包就大功告成了。

            <plugin>
                <artifactId>maven-shade-plugin</artifactId>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.jimo.tool.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值