Java命令行开发工具-JCommander 使用
前言(有点长)
工作中开发需求,需要设计一个引擎包,将内部工具封装起来,为插件或者 desktop 应用提供核心功能。项目开启时间较为紧迫,从熟悉的 java 着手研究……
首先,应该思考 java 的 main 方法,程序的入口,idea 开发习惯了,老是 psvm 快捷方式创建,但是其中的原理,对于每个关键词的理解,是否只能以 main 方法为程序入口……思考的就远了
public static void main(String[] args){
/**
* public 权限修饰符,公共的,在任何地方都有调用的权限,没有包、类、继承关系的限制
* static 静态 关键字,被 static 修饰的成员或方法不需要创建对象就能通过类名调用,存在生命周期较长
* void 关键字,没有返回值
* String[] args 参数,字符串数组
*/
}
之前在最开始学 c语言开发的时候,提出过一个问题,程序的入口必须是 main 方法吗?我可以自定义程序的入口吗?…… 学过汇编语言的朋友应该会知道,方法(函数)的调用,就是通过 call 指令,跳转到指定的内存地址,c 代码经过编译之后,转成 汇编语言,汇编程序设定的 main 函数的入口就是指定的内存地址, 如果我们修改 内存地址的值为自定义的函数起始地址,那就可以指定函数入口了…… 说的有点远了
回到 main 方法本身,谁来调用它,并且给它传参?毫无疑问 是Java虚拟机
String[] args 参数,来接收执行java命令时所运行的类的参数
java -jar test.jar --help
“–help” 就是作为参数,由String[] args接收
技术选型 – JCommander
官网:http://jcommander.org/ 具体使用参考 官网,且已有很多中文版翻译,可参考等,网上挺多基本解释的
Java集成使用
依赖
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.71</version>
</dependency>
以下是我在使用过程中做的一些封装,自己使用,做记录的
MyJcmd 主类,程序入口类
package org.example;
public class MyJcmd {
public static void main(String[] args) {
StatusCode statusCode;
if (args.length > 0){
MyJcmdParserResult result = MyJcmdParserResult.extractParameter(new MyJcmdParameter(),args );
if (result.isHelp()){
MyJcmdHelp.showHelpInfo(result.getParameter());
statusCode = StatusCode.OK;
}else if (result.isVersion()){
System.out.println(MyJcmdVersion.VERSION);
statusCode = StatusCode.OK;
}else if (!result.isError()){
// todo 就可以执行设定的命令操作了,操作返回 状态码表示命令 action 的运行成功或者失败
statusCode = StatusCode.OK;
}else {
System.err.println("Please use --help for help");
statusCode = StatusCode.ERROR;
}
if (statusCode == StatusCode.OK){
// 正常结束
System.exit(0);
}
}
// 异常结束
System.exit(1);
}
enum StatusCode{
OK,
ERROR,
;
}
}
对 结果的封装类
package org.example;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import lombok.Data;
@Data
public class MyJcmdParserResult {
private MyJcmdParameter parameter;
private ParameterException exception;
public MyJcmdParserResult(MyJcmdParameter parameter){
this.parameter = parameter;
}
public MyJcmdParserResult(ParameterException e){
this.exception = e;
}
public boolean isError(){
return exception != null;
}
public boolean isHelp(){
return !isError() && parameter.isHelp();
}
public boolean isVersion(){
return !isError() && parameter.isVersion();
}
public boolean isDebug(){
return !isError() && parameter.isDebug();
}
/**
* 解析命令行输入的参数
* @param parameter 参数对象,将输入的命令数组转为对象
* @param args 命令数组
* @return
*/
public static MyJcmdParserResult extractParameter(MyJcmdParameter parameter,String... args){
JCommander jCommander = new JCommander();
jCommander.addCommand(parameter);
jCommander.setProgramName("example");
try {
jCommander.parse(args);
return new MyJcmdParserResult(parameter);
} catch (ParameterException e) {
e.printStackTrace();
return new MyJcmdParserResult(e);
}
}
}
处理 help 信息
package org.example;
import com.beust.jcommander.JCommander;
import java.util.List;
public class MyJcmdHelp {
public static void showHelpInfo(MyJcmdParameter parameter){
List<String> parameters = parameter.getParameters();
String info;
if (!parameters.isEmpty()){
JCommander jCommander = new JCommander();
jCommander.addCommand(parameter);
jCommander.usage();
return;
}else {
info = "No application operate,Please --help";
}
System.err.println(info);
}
}
处理 version
package org.example;
import lombok.Data;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
@Data
public final class MyJcmdVersion {
public static final String VERSION;
public static final String UNKNOWN_VERSION = "unknown";
static {
String version = UNKNOWN_VERSION;
try (InputStream stream = MyJcmdVersion.class.getResourceAsStream("/META-INF/maven/org.example/**/pom.properties")){
// 此处的 ** 是 你的包 pom 文件中 artifactId 的内容,可以打包后解压展开查看
if (stream != null){
Properties properties = new Properties();
properties.load(stream);
version = properties.getProperty("version");
}
} catch (IOException e) {
System.err.println("cannot get the version");
}
VERSION = version;
}
private MyJcmdVersion(){
throw new AssertionError("cannot get the version");
}
}
参数类
package org.example;
import com.beust.jcommander.Parameter;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class MyJcmdParameter {
// todo 写在前边,参数可支持的类型有很多,可以到官网查看要使用的类型,一般 String 较多
@Parameter(description = "命令前缀")
List<String> parameters = new ArrayList<>();
@Parameter(names = {"--help","-h"},
description = "帮助"
)
private boolean help;
@Parameter(names = {"--version","-v"},
description = "版本"
)
private boolean version;
@Parameter(names = {"--debug","-debug"},
description = "调试模式"
)
private boolean debug;
//todo 这里可以定义属性,接收参数的形式
// 或者,定义其他各个操作的类接收的参数,继承此类,各个类有自己的参数管理
}
这是打包后,写的 mycmd.bat 批处理文件内容,
@echo off
set TOPDIR="%~dp0.."
set EXCUDIR="%~dp0"
set MAIN_CLASS=org.example.MyJcmd
set path=%TOPDIR%\jdk\bin;%EXCUDIR%;%PATH%
java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %*
可以直接在控制台执行
mycmd --help
就可以使用了
注意,bat 文件和 jar 包的路径,我是这样的路径:
- bin
- mycmd.bat
- lib
- mycmd.jar
注意写脚本的相对路径位置,jar包的名称无所谓可以随便取,不一定非要和 bat 文件名称相同
下面提供一种在 idea 中可以直接调试使用的方式
ok,结束!