使用 JCommander 解析命令行参数
前言
如果你想构建一个支持命令行参数的程序,那么 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 引入
截止文章编写时间,最新版本如下:
<!-- 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 也提供了特有的参数验证方式。
编写参数验证类,需要实现
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<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> {
@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<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.
本文 Github.com/niumoo/JavaNotes仓库已经收录。
本文原发于网站:https://www.wdbyte.com/tool/jcommander/
我的公众号:使用 JCommander 解析命令行参数
使用 JCommander 解析命令行参数的更多相关文章
- boost之program_options库,解析命令行参数、读取配置文件
一.命令行解析 tprogram_options解析命令行参数示例代码: #include <iostream> using namespace std; #include <boo ...
- optparse模块解析命令行参数的说明及优化
一.关于解析命令行参数的方法 关于“解析命令行参数”的方法我们一般都会用到sys.argv跟optparse模块.关于sys.argv,网上有一篇非常优秀的博客已经介绍的很详细了,大家可以去这里参考: ...
- python解析命令行参数
常常需要解析命令行参数,经常忘记,好烦,总结下来吧. 1.Python 中也可以所用 sys 的 sys.argv 来获取命令行参数: sys.argv 是命令行参数列表 参数个数:len(sys.a ...
- linux 中解析命令行参数(getopt_long用法)
linux 中解析命令行参数(getopt_long用法) http://www.educity.cn/linux/518242.html 详细解析命令行的getopt_long()函数 http:/ ...
- C语言中使用库函数解析命令行参数
在编写需要命令行参数的C程序的时候,往往我们需要先解析命令行参数,然后根据这些参数来启动我们的程序. C的库函数中提供了两个函数可以用来帮助我们解析命令行参数:getopt.getopt_long. ...
- Windows下解析命令行参数
linux通常使用GNU C提供的函数getopt.getopt_long.getopt_long_only函数来解析命令行参数. 移植到Windows下 getopt.h #ifndef _GETO ...
- 3.QT中QCommandLineParser和QCommandLineOption解析命令行参数
1 新建项目 main.cpp #include <QCoreApplication> #include <QCommandLineParser> #include & ...
- 使用 Apache Commons CLI 解析命令行参数示例
很好的输入参数解析方法 ,转载记录下 转载在: https://www.cnblogs.com/onmyway20xx/p/7346709.html Apache Commons CLI 简介 Apa ...
- Shell 参数(2) --解析命令行参数工具:getopts/getopt
getopt 与 getopts 都是 Bash 中用来获取与分析命令行参数的工具,常用在 Shell 脚本中被用来分析脚本参数. 两者的比较 (1)getopts 是 Shell 内建命令,geto ...
- getopt_long函数解析命令行参数
转载:http://blog.csdn.net/hcx25909/article/details/7388750 每一天你都在使用大量的命令行程序,是不是感觉那些命令行参数用起来比较方便,他们都是使用 ...
随机推荐
- kubernetes(k8s)中部署 efk
Kubernetes 开发了一个 Elasticsearch 附加组件来实现集群的日志管理.这是一个 Elasticsearch.Fluentd 和 Kibana 的组合. Elasticsearch ...
- stm32串口烧录程序
Step1:将BOOT0设置为1,BOOT1设置为0,mcuisp软件不使用STR和DTR烧录 Step2:程序下载完成后,再将BOOT0手动跳帽接GND,复位,这样STM32才可以从Flash中启动 ...
- Java中「Future」接口详解
目录 一.背景 二.Future接口 1.入门案例 2.Future接口 三.CompletableFuture类 1.基础说明 2.核心方法 2.1 实例方法 2.2 计算方法 2.3 结果获取方法 ...
- 零样本文本分类应用:基于UTC的医疗意图多分类,打通数据标注-模型训练-模型调优-预测部署全流程。
零样本文本分类应用:基于UTC的医疗意图多分类,打通数据标注-模型训练-模型调优-预测部署全流程. 1.通用文本分类技术UTC介绍 本项目提供基于通用文本分类 UTC(Universal Text C ...
- ROS用hector创建地图
ROS用hector创建地图 连接小车 ssh clbrobot@clbrobot 激活树莓派 roslaunch clbrobot bringup.launch 打开hector_slam 重新开终 ...
- JS 实现关键字文本搜索 高亮显示
示例: 利用字符串的 split 方法,通过搜索的关键字分割成数组 在利用数组的 join 方法拼接成字符串 我是利用mock的省份 1 <template> 2 <div cl ...
- [OpenCV-Python] 7 把鼠标当画笔
文章目录 OpenCV-Python: II OpenCV 中的 Gui 特性 7 把鼠标当画笔 7.1 简单演示 7.2 高级一点的示例 OpenCV-Python: II OpenCV 中的 Gu ...
- SQL Server数据库判断最近一次的备份执行结果
1 麻烦的地方 在SQL Server的官方文档里面可以看到备份和还原的表,但是这些表里面只能找到备份成功的相关信息,无法找到备份失败的记录,比如msdb.dbo.backupset.对于一些监控系统 ...
- Solon v2.2.17 发布,Java 新的生态型应用开发框架
相对于 Spring Boot 和 Spring Cloud 的项目: 启动快 5 - 10 倍. (更快) qps 高 2- 3 倍. (更高) 运行时内存节省 1/3 ~ 1/2. (更少) 打包 ...
- < Python全景系列-4 > 史上最全文件类型读写库大盘点!什么?还包括音频、视频?
欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语言! 本文系列第四篇,介绍史上 ...