JCommander解析命令行參數(shù)使用詳解
前言
如果你想構(gòu)建一個(gè)支持命令行參數(shù)的程序,那么 jcommander 非常適合你,jcommander 是一個(gè)只有幾十 kb 的 Java 命令行參數(shù)解析工具,可以通過(guò)注解的方式快速實(shí)現(xiàn)命令行參數(shù)解析。
這篇教程會(huì)通過(guò)介紹 jcommadner ,快速的創(chuàng)建一個(gè)命令行程序,最后支持的命令參數(shù)功能如下圖。
這個(gè)命令行工具仿照 git 操作命令,主要提供了如下功能命令:
git-app.jar -help
查看命令幫助信息。git-app.jar -version
查看當(dāng)前版本號(hào)。git-app.jar clone http://xxxx
通過(guò) URL 克隆一個(gè)倉(cāng)庫(kù)。git-app.jar add file1 file2
暫存 file1 文件 file2 文件。git-app.jar commit -m "注釋"
提交并添加注釋。
jcommander 引入
截止文章編寫(xiě)時(shí)間,最新版本如下:
<!-- https://mvnrepository.com/artifact/com.beust/jcommander --> <dependency> <groupId>com.beust</groupId> <artifactId>jcommander</artifactId> <version>1.82</version> </dependency>
jcommander 參數(shù)綁定
命令行解析中,參數(shù)解析與綁定是最實(shí)用的一個(gè)場(chǎng)景,jcommander 使用 Parameter
注解進(jìn)行參數(shù)綁定。我們定義一個(gè) GitCommandOptions.java
類(lèi)來(lái)測(cè)試參數(shù)綁定。
package com.wdbyte.jcommander.v1; import com.beust.jcommander.Parameter; /** * @author https://www.wdbyte.com */ public class GitCommandOptions { @Parameter(names = {"clone"}, description = "克隆遠(yuǎn)程倉(cāng)庫(kù)數(shù)據(jù)") private String cloneUrl; public String getCloneUrl() { return cloneUrl; } }
使用 jcommander 結(jié)合 GitCommandOptions 來(lái)解析參數(shù)。
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()); } }
打包后可以執(zhí)行命令參數(shù):
$ java -jar git-app.jar clone http://www.wdbyte.com/test.git clone http://www.wdbyte.com/test.git
這里是一個(gè)字符串參數(shù),需要在命令中輸出參數(shù)值,對(duì)于 boolean 類(lèi)型的參數(shù),不需要傳值,有命令即為 true 值。
參數(shù)名稱(chēng)
@Parameter
注解中的 names
屬性可以定義參數(shù)的名稱(chēng)。且可以指定多個(gè)參數(shù)名稱(chēng),讓我再添加 version
參數(shù)和 help
參數(shù),同時(shí)設(shè)置參數(shù)別名。這兩個(gè)參數(shù)是 boolean 類(lèi)型。
@Parameter(names = {"help", "-help", "-h"}, description = "查看幫助信息", help = true) private boolean help; @Parameter(names = {"version", "-version", "-v"}, description = "顯示當(dāng)前版本號(hào)") private boolean version = false;
參數(shù)限制
clone
參數(shù)可以接受一個(gè)要克隆的 URL 鏈接,但是正常情況下只需要一個(gè) URL 鏈接??梢酝ㄟ^(guò) arity = 1
進(jìn)行限制。
@Parameter(names = {"clone"}, description = "克隆遠(yuǎn)程倉(cāng)庫(kù)數(shù)據(jù)", arity = 1) private String cloneUrl;
幫助信息
使用 usage()
參數(shù)可以打印命令幫助信息。
GitCommandOptions gitCommandOptions = new GitCommandOptions(); JCommander commander = JCommander.newBuilder() .addObject(gitCommandOptions) .build(); commander.parse(args); // 打印幫助信息 commander.usage();
運(yùn)行輸出幫助信息:
$ java -jar git-app.jar Usage: <main class> [options] Options: clone 克隆遠(yuǎn)程倉(cāng)庫(kù)數(shù)據(jù) help, -help, -h 查看幫助信息 version, -version, -v 顯示當(dāng)前版本號(hào) Default: false
雖然正確的輸出了幫助信息,但是其中有 main class
這段,是因?yàn)槲覀儧](méi)有指定項(xiàng)目名稱(chēng),我們指定項(xiàng)目名稱(chēng)為 git-app
。
JCommander commander = JCommander.newBuilder() .programName("git-app") .addObject(gitCommandOptions) .build();
參數(shù)排序
在幫助信息中,如果想要自定義參數(shù)順序,可以通過(guò) order =
來(lái)排序,數(shù)字越小越靠前。
@Parameter(names = {"version", "-version", "-v"}, description = "顯示當(dāng)前版本號(hào)", order = 2) private boolean version = false;
參數(shù)綁定完整測(cè)試
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 = "克隆遠(yuǎn)程倉(cāng)庫(kù)數(shù)據(jù)", order = 3, arity = 1) private String cloneUrl; @Parameter(names = {"version", "-version", "-v"}, description = "顯示當(dāng)前版本號(hào)", 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()); } } }
運(yùn)行測(cè)試:
jcommander 參數(shù)驗(yàn)證
在上面的例子中, 假設(shè) clone 命令傳入的參數(shù)必須是一個(gè) URL,那么我們就要進(jìn)行參數(shù)驗(yàn)證,jcommander 也提供了特有的參數(shù)驗(yàn)證方式。
編寫(xiě)參數(shù)驗(yàn)證類(lèi),需要實(shí)現(xiàn) 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("參數(shù) " + key + " 的值必須是 URL 格式"); } } }
clone
參數(shù)指定驗(yàn)證類(lèi)。
@Parameter(names = {"clone"}, description = "克隆遠(yuǎn)程倉(cāng)庫(kù)數(shù)據(jù)", validateWith = UrlParameterValidator.class, order = 3, arity = 1) private String cloneUrl;
運(yùn)行測(cè)試:
$ 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: 參數(shù) 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 時(shí),我們經(jīng)常會(huì)使用下面兩個(gè)命令。
git add file1 file2
暫存 file1 文件 file2 文件。git commit -m "注釋"
提交并添加注釋。
什么是子命令
這是一種很常見(jiàn)的操作,git commit
除了可以跟 -m
子參數(shù)外,還可以跟各種參數(shù),通過(guò) 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>...]
這種有子參數(shù)的情況,我們可以稱(chēng) commit
為 git 的一個(gè)子命令,使用 jcommander 如何配置子命令呢?
jcommander 子命令實(shí)現(xiàn)
我們新增子命令對(duì)應(yīng)的參數(shù)類(lèi) 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 = "請(qǐng)輸入注釋", arity = 1, required = true) private String comment; public String getComment() { return comment; } }
代碼中使用 @Parameters
注解指定了子命令為 commit
,同時(shí)使用 @Paramete
注解指定子參數(shù) -m
,同時(shí) -m
參數(shù)是必須的,使用屬性 required = true
來(lái)指定。
使用 GitCommandCommit:
使用 addCommand
添加 Commit
命令參數(shù)類(lèi)。
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()); }
運(yùn)行測(cè)試:
$ java -jar git-app.jar commit -m '注釋一下' 注釋一下
同上,我們可以添加 add
命令對(duì)應(yīng)的參數(shù)類(lèi):GitCommandAdd.java
. 這次我們定義一個(gè) List 類(lèi)型參數(shù),但是不在屬性上指定子參數(shù)名稱(chēng)。
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); } }
運(yùn)行測(cè)試:
$ java -jar git-app.jar add file1.txt file2.txt 暫存文件:file1.txt 暫存文件:file2.txt
jcommander 參數(shù)轉(zhuǎn)換
在上面的 GitCommandAdd
代碼中,add
命令傳入的都是文件路徑,現(xiàn)在是使用 List<String>
來(lái)接收入?yún)?,通常情況想我們可能需要直接轉(zhuǎn)換成方便操作的類(lèi)型,如 File 或者 Path,這該如何方面的轉(zhuǎn)換呢,jcommander 也提供了方便轉(zhuǎn)換類(lèi)。
首先編寫(xiě)一個(gè)轉(zhuǎn)換類(lèi) FilePathConverter 用于把入?yún)⑥D(zhuǎn)換成 Path 類(lèi),同時(shí)校驗(yàn)文件是否存在
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)); } }
通過(guò)注解指定轉(zhuǎn)換類(lèi):
@Parameter(description = "暫存文件列表", converter = FilePathConverter.class) private List<Path> files;
打包測(cè)試:
$ 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
總體測(cè)試
一如既往,文章代碼都存放在 Github.com/niumoo/javaNotes.
相關(guān)文章
詳解簡(jiǎn)單基于spring的redis配置(單機(jī)和集群模式)
這篇文章主要介紹了詳解簡(jiǎn)單基于spring的redis配置(單機(jī)和集群模式),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02JAVA實(shí)現(xiàn)二維碼生成加背景圖代碼實(shí)例
這篇文章主要介紹了JAVA實(shí)現(xiàn)二維碼生成加背景圖代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Java Builder Pattern建造者模式詳解及實(shí)例
這篇文章主要介紹了Java Builder Pattern建造者模式詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-01-01@Bean注解和@Configuration、@Component注解組合使用的區(qū)別
這篇文章主要介紹了@Bean注解和@Configuration、@Component注解組合使用的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11IDEA啟動(dòng)tomcat項(xiàng)目報(bào)錯(cuò)53820 socket closed問(wèn)題及解決
IDEA啟動(dòng)Tomcat項(xiàng)目時(shí)報(bào)錯(cuò),原因是IDEA關(guān)閉時(shí)Tomcat未正常關(guān)閉,導(dǎo)致端口被占用,解決方法是通過(guò)任務(wù)管理器關(guān)閉占用高內(nèi)存的Java進(jìn)程,通常是IDEA進(jìn)程下面的,或者使用命令行找到PID并強(qiáng)制終止進(jìn)程2024-12-12MyBatis實(shí)現(xiàn)樂(lè)觀鎖和悲觀鎖的示例代碼
在數(shù)據(jù)庫(kù)操作中,樂(lè)觀鎖和悲觀鎖是兩種常見(jiàn)的并發(fā)控制策略,本文主要介紹了MyBatis實(shí)現(xiàn)樂(lè)觀鎖和悲觀鎖的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07Java模擬HTTP Get Post請(qǐng)求實(shí)現(xiàn)論壇自動(dòng)回帖功能
這篇文章主要介紹了Java模擬HTTP Get Post請(qǐng)求實(shí)現(xiàn)論壇自動(dòng)回帖功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09