使用 JCommander 解析命令行参数

前言

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

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

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

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

jcommander 引入

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

<!-- https://mvnrepository.com/artifact/com.beust/jcommander -->
<dependency><groupId>com.beust</groupId><artifactId>jcommander</artifactId><version>1.82</version>
</dependency>

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: <main class> [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 也提供了特有的参数验证方式。

  1. 编写参数验证类,需要实现 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 {@Overridepublic void validate(String key, String value) throws ParameterException {try {new URL(value);} catch (MalformedURLException e) {throw new ParameterException("参数 " + key + " 的值必须是 URL 格式");}}
    }
    
  2. 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 时,我们经常会使用下面两个命令。

  1. git add file1 file2 暂存 file1 文件 file2 文件。
  2. git commit -m "注释" 提交并添加注释。

什么是子命令

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

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

这种有子参数的情况,我们可以称 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<String> files;public List<String> 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<String> 来接收入参,通常情况想我们可能需要直接转换成方便操作的类型,如 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<Path> {@Overridepublic 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<Path> 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

总体测试

一如既往,文章代码都存放在 Github.com/niumoo/javaNotes.

参考:https://jcommander.org/

本文 Github.com/niumoo/JavaNotes仓库已经收录。
本文原发于网站:https://www.wdbyte.com/tool/jcommander/
我的公众号:使用 JCommander 解析命令行参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1834.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rabbit MQ的基本使用

目录 1. MQ是什么&#xff0c;有哪些作用&#xff1f; 2. 主要的MQ框架有哪些&#xff1f; 3. RabbitMQ安装 4. RabbitMQ中的主要概念 5. 消息队列的核心概念 6. 一个简单的生产者和消费者示例 6.1 消息发送者模块 6.1.1 引入必要的依赖 6.1.2 项目配置文件 6.1.3 启动…

【探索 Kubernetes|作业管理篇 系列 14】StatefulSet 存储状态

前言 大家好&#xff0c;我是秋意零。 在上一篇中&#xff0c;我们讲解了 StatefulSet 的拓扑状态&#xff1b;我们发现&#xff0c;它的拓扑状态&#xff0c;就是顺序启动/删除、Pod 名称编号命名、将 Pod 名称设为 Hostname 名称、通过 Service 无头服务的 DNS 记录访问。 …

uniapp打包app后,微信授权登录

官方文档&#xff1a;App端OAuth(登录鉴权)模块 关键配置项说明&#xff1a; 1、appid 微信开放平台申请应用的AppID值。 2、appSecret&#xff08;HBuilderX3.4.18 不再提供此参数的可视化配置&#xff09; 微信开放平台申请应用的AppSecret值。 找到manifest.json文件&am…

网络安全 | 密码基础知识介绍

概述 密码介绍 安全问题 保密性&#xff1a;对发送的消息进行获取完整性&#xff1a;对发送的消息进行篡改身份伪造&#xff1a;对发送的主体身份进行篡改&#xff0c;a发的消息&#xff0c;篡改为b发的行为抵赖&#xff1a;对发送的消息进行否认&#xff0c;丧失行为的可追…

SQL 优化(三):使用覆盖索引

摘要 今天跟大家分享一个比较常见的 SQL 优化手段——使用覆盖索引。需要特殊说明的是&#xff0c;MySQL 支持多种存储引擎&#xff0c;对索引的支持也不同&#xff0c;这里我们只关注 InnoDB 引擎的 BTree 索引 InnoDB 的索引实现 在介绍覆盖索引之前&#xff0c;我们先简单…

【MySQL】MVCC是如何解决快照读下的幻读问题的

文章目录 LBCC当前读 MVCC隐藏列undo logRead View 总结 我们从上文中了解到InnoDB默认的事务隔离级别是repeatable read&#xff08;后文中用简称RR&#xff09;&#xff0c;它为了解决该隔离级别下的幻读的并发问题&#xff0c;提出了LBCC和MVCC两种方案。其中LBCC解决的是当…

SAP 区分工单BOM物料是手工删除 还是 Teco后自动关闭需求

SAP 区分工单BOM物料是手工删除 还是 Teco后自动关闭需求 首先 resb表删除标识XLOEK 都为 ‘X’&#xff0c;无法通过其它字段直接区分 1先从前台界面区分 手工删除的&#xff0c;组件界面颜色正常&#xff0c;状态为-REL 删除 Teco自动关闭需求的&#xff0c;颜色不一样&am…

MAC电脑使用技巧

Mac打开根目录 /user下的文件 mac 上怎么显示隐藏的/user文件夹&#xff0c;有两种方法可选~~~ 1&#xff0c;Finder界面是&#xff0c;最上方&#xff0c;通过“前往”进入“电脑”或文件夹 先进入到需要显示隐藏文件的文件夹下 接着按Command苹果键F,在窗格上会显示搜索栏 然…

OpenCV(图像处理)-基于Python-轮廓查找

轮廓查找 1. 轮廓2.轮廓查找2.1 findContours()2.2 drawContours()2.3 contourArea()和arcLength()2.4 多边形逼近与凸包approxPolyDP()convexHull()2.5 外接矩形minAreaRect()boundingRect() 1. 轮廓 一个图像中具有相同颜色或强度&#xff08;灰度图&#xff09;的连续点所组…

springboot配置https

本身不是一个挺难的东西&#xff0c;但是也踩了很多坑&#xff0c;终于是可以了&#xff0c;在此记录一下。 就两步生成证书和springboot配置。 目录 1.生成证书2.springboot配置3.启动验证注意事项 1.生成证书 这里采用java自带的keytool进行生成。 注意jdk环境&#xff0c;…

最新,2023年6月CDGP设计及论述题解析

2023年6月CDGP设计及论述题解析 &#xff08;加gzh“大数据食铁兽”&#xff0c;回复“2023cdgp”获取完整版&#xff09; 酒店会员建模 结合国内外数据安全法律法规&#xff0c;谈谈境外传输数据安全管理体系建设 国内&#xff1a;《数据安全法》、《网络安全法》、2022年9月…

基于深度学习的高精度打电话检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度打电话检测识别系统可用于日常生活中或野外来检测与定位打电话目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的打电话目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检…