使用 JCommander 解析命令行参数

您所在的位置:网站首页 cad加载小程序命令 使用 JCommander 解析命令行参数

使用 JCommander 解析命令行参数

2023-07-08 16:52| 来源: 网络整理| 查看: 265

前言

如果你想构建一个支持命令行参数的程序,那么 jcommander 非常适合你,jcommander 是一个只有几十 kb 的 Java 命令行参数解析工具,可以通过注解的方式快速实现命令行参数解析。

这篇教程会通过介绍 jcommadner ,快速的创建一个命令行程序,最后支持的命令参数功能如下图。

这个命令行工具仿照 git 操作命令,主要提供了如下功能命令:

git-app.jar -help 查看命令帮助信息。git-app.jar -version 查看当前版本号。git-app.jar clone http://xxxx 通过 URL 克隆一个仓库。git-app.jar add file1 file2 暂存 file1 文件 file2 文件。git-app.jar commit -m "注释" 提交并添加注释。 jcommander 引入

截止文章编写时间,最新版本如下:

com.beust jcommander 1.82 jcommander 参数绑定

命令行解析中,参数解析与绑定是最实用的一个场景,jcommander 使用 Parameter 注解进行参数绑定。我们定义一个 GitCommandOptions.java 类来测试参数绑定。

package com.wdbyte.jcommander.v1; import com.beust.jcommander.Parameter; /** * @author https://www.wdbyte.com */ public class GitCommandOptions { @Parameter(names = {"clone"}, description = "克隆远程仓库数据") private String cloneUrl; public String getCloneUrl() { return cloneUrl; } }

使用 jcommander 结合 GitCommandOptions 来解析参数。

package com.wdbyte.jcommander.v1; import com.beust.jcommander.JCommander; /** * @author https://www.wdbyte.com */ public class GitApp { public static void main(String[] args) { // args = new String[]{"clone","http://www.wdbyte.com/test.git"}; GitCommandOptions gitCommandOptions = new GitCommandOptions(); JCommander commander = JCommander.newBuilder() .addObject(gitCommandOptions) .build(); commander.parse(args); System.out.println("clone " + gitCommandOptions.getCloneUrl()); } }

打包后可以执行命令参数:

$ java -jar git-app.jar clone http://www.wdbyte.com/test.git clone http://www.wdbyte.com/test.git

这里是一个字符串参数,需要在命令中输出参数值,对于 boolean 类型的参数,不需要传值,有命令即为 true 值。

参数名称

@Parameter 注解中的 names 属性可以定义参数的名称。且可以指定多个参数名称,让我再添加 version 参数和 help 参数,同时设置参数别名。这两个参数是 boolean 类型。

@Parameter(names = {"help", "-help", "-h"}, description = "查看帮助信息", help = true) private boolean help; @Parameter(names = {"version", "-version", "-v"}, description = "显示当前版本号") private boolean version = false; 参数限制

clone 参数可以接受一个要克隆的 URL 链接,但是正常情况下只需要一个 URL 链接。可以通过 arity = 1 进行限制。

@Parameter(names = {"clone"}, description = "克隆远程仓库数据", arity = 1) private String cloneUrl; 帮助信息

使用 usage() 参数可以打印命令帮助信息。

GitCommandOptions gitCommandOptions = new GitCommandOptions(); JCommander commander = JCommander.newBuilder() .addObject(gitCommandOptions) .build(); commander.parse(args); // 打印帮助信息 commander.usage();

运行输出帮助信息:

$ java -jar git-app.jar Usage: [options] Options: clone 克隆远程仓库数据 help, -help, -h 查看帮助信息 version, -version, -v 显示当前版本号 Default: false

虽然正确的输出了帮助信息,但是其中有 main class 这段,是因为我们没有指定项目名称,我们指定项目名称为 git-app。

JCommander commander = JCommander.newBuilder() .programName("git-app") .addObject(gitCommandOptions) .build(); 参数排序

在帮助信息中,如果想要自定义参数顺序,可以通过 order = 来排序,数字越小越靠前。

@Parameter(names = {"version", "-version", "-v"}, description = "显示当前版本号", order = 2) private boolean version = false; 参数绑定完整测试 package com.wdbyte.jcommander.v2; import com.beust.jcommander.Parameter; /** * @author https://www.wdbyte.com */ public class GitCommandOptions { @Parameter(names = {"help", "-help", "-h"}, description = "查看帮助信息", order = 1, help = true) private boolean help; @Parameter(names = {"clone"}, description = "克隆远程仓库数据", order = 3, arity = 1) private String cloneUrl; @Parameter(names = {"version", "-version", "-v"}, description = "显示当前版本号", order = 2) private boolean version = false; //...get method }

GitApp.java

package com.wdbyte.jcommander.v2; import com.beust.jcommander.JCommander; public class GitApp { public static void main(String[] args) { GitCommandOptions gitCommandOptions = new GitCommandOptions(); JCommander commander = JCommander.newBuilder() .programName("git-app") .addObject(gitCommandOptions) .build(); commander.parse(args); // 打印帮助信息 if (gitCommandOptions.isHelp()) { commander.usage(); return; } if (gitCommandOptions.isVersion()) { System.out.println("git version 2.24.3 (Apple Git-128)"); return; } if (gitCommandOptions.getCloneUrl() != null) { System.out.println("clone " + gitCommandOptions.getCloneUrl()); } } }

运行测试:

jcommander 参数验证

在上面的例子中, 假设 clone 命令传入的参数必须是一个 URL,那么我们就要进行参数验证,jcommander 也提供了特有的参数验证方式。

编写参数验证类,需要实现 IParameterValidator 接口。

package com.wdbyte.jcommander.v3; import java.net.MalformedURLException; import java.net.URL; import com.beust.jcommander.IParameterValidator; import com.beust.jcommander.ParameterException; /** * @author https://www.wdbyte.com */ public class UrlParameterValidator implements IParameterValidator { @Override public void validate(String key, String value) throws ParameterException { try { new URL(value); } catch (MalformedURLException e) { throw new ParameterException("参数 " + key + " 的值必须是 URL 格式"); } } }

clone 参数指定验证类。

@Parameter(names = {"clone"}, description = "克隆远程仓库数据", validateWith = UrlParameterValidator.class, order = 3, arity = 1) private String cloneUrl;

运行测试:

$ java -jar git-app.jar clone https://www.wdbyte.com/test.git clone https://www.wdbyte.com/test.git $ java -jar git-app.jar clone test.git Exception in thread "main" com.beust.jcommander.ParameterException: 参数 clone 的值必须是 URL 格式 at com.wdbyte.jcommander.v3.UrlParameterValidator.validate(UrlParameterValidator.java:19) at com.beust.jcommander.ParameterDescription.validateParameter(ParameterDescription.java:377) at com.beust.jcommander.ParameterDescription.validateParameter(ParameterDescription.java:344) jcommander 子命令

在使用 git 时,我们经常会使用下面两个命令。

git add file1 file2 暂存 file1 文件 file2 文件。git commit -m "注释" 提交并添加注释。 什么是子命令

这是一种很常见的操作,git commit 除了可以跟 -m 子参数外,还可以跟各种参数,通过 git 帮助文档可以看到。

git commit [-a | --interactive | --patch] [-s] [-v] [-u] [--amend] [--dry-run] [(-c | -C | --fixup | --squash) ] [-F | -m ] [--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify] [-e] [--author=] [--date=] [--cleanup=] [--[no-]status] [-i | -o] [-S[]] [--] [...]

这种有子参数的情况,我们可以称 commit 为 git 的一个子命令,使用 jcommander 如何配置子命令呢?

jcommander 子命令实现

我们新增子命令对应的参数类 GitCommandCommit.java.

package com.wdbyte.jcommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; /** * git commit -m "desc" * @author https://www.wdbyte.com */ @Parameters(commandDescription = "提交文件", commandNames = "commit") public class GitCommandCommit { public static final String COMMAND = "commit"; @Parameter(names = {"-comment", "-m"}, description = "请输入注释", arity = 1, required = true) private String comment; public String getComment() { return comment; } }

代码中使用 @Parameters 注解指定了子命令为 commit,同时使用 @Paramete 注解指定子参数 -m,同时 -m 参数是必须的,使用属性 required = true 来指定。

使用 GitCommandCommit:

使用 addCommand 添加 Commit 命令参数类。

GitCommandOptions gitCommandOptions = new GitCommandOptions(); GitCommandCommit commandCommit = new GitCommandCommit(); JCommander commander = JCommander.newBuilder() .programName("git-app") .addObject(gitCommandOptions) .addCommand(commandCommit) .build(); commander.parse(args); String parsedCommand = commander.getParsedCommand(); if ("commit".equals(parsedCommand)) { System.out.println(commandCommit.getComment()); }

运行测试:

$ java -jar git-app.jar commit -m '注释一下' 注释一下

同上,我们可以添加 add 命令对应的参数类:GitCommandAdd.java. 这次我们定义一个 List 类型参数,但是不在属性上指定子参数名称。

package com.wdbyte.jcommander.v5; import java.util.List; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; /** * git add file1 file2 * * @author https://www.wdbyte.com */ @Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ") public class GitCommandAdd { public static final String COMMAND = "add"; @Parameter(description = "暂存文件列表") private List files; public List getFiles() { return files; } }

同样添加到子命令:

JCommander commander = JCommander.newBuilder() .programName("git-app") .addObject(gitCommandOptions) .addCommand(commandCommit) .addCommand(commandAdd) .build(); commander.parse(args); if ("add".equals(parsedCommand)) { for (String file : commandAdd.getFiles()) { System.out.println("暂存文件:" + file); } }

运行测试:

$ java -jar git-app.jar add file1.txt file2.txt 暂存文件:file1.txt 暂存文件:file2.txt jcommander 参数转换

在上面的 GitCommandAdd 代码中,add 命令传入的都是文件路径,现在是使用 List 来接收入参,通常情况想我们可能需要直接转换成方便操作的类型,如 File 或者 Path,这该如何方面的转换呢,jcommander 也提供了方便转换类。

首先编写一个转换类 FilePathConverter 用于把入参转换成 Path 类,同时校验文件是否存在

package com.wdbyte.jcommander; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.ParameterException; /** * * @author https://www.wdbyte.com */ public class FilePathConverter implements IStringConverter { @Override public Path convert(String filePath) { Path path = Paths.get(filePath); if (Files.exists(path)) { return path; } throw new ParameterException(String.format("文件不存在,path:%s", filePath)); } }

通过注解指定转换类:

@Parameter(description = "暂存文件列表", converter = FilePathConverter.class) private List files;

打包测试:

$ java -jar git-app.jar add file1 file2 文件不存在,path:file1 $ ls -l total 12448 drwxr-xr-x 2 darcy staff 64B 6 15 21:10 archive-tmp drwxr-xr-x 3 darcy staff 96B 6 15 21:10 classes drwxr-xr-x 3 darcy staff 96B 6 15 21:10 generated-sources -rw-r--r-- 1 darcy staff 5.6M 6 16 20:44 git-app.jar $ git-app.jar git-app.jar 暂存文件:git-app.jar 总体测试



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3