怎么基于Java编写一个CLI工具?( 二 )


  • DefaultParser:提供了基础的解析功能,能解析简单的命令行参数 。(比如:java -Djava.awt.headless=true -Djava.NET.useSystemProxies=true Foo)
  • PosixParser:提供了解析POSIX形式参数的功能 。(比如:tar -zxvf foo.tar.gz)
  • GnuParser:提供了解析长参数及Java命令中参数的功能 。(比如:du --human-readable --max-depth=1)
询问阶段基于上一步解析后,会将参数解析成CommandLine,结合Option中的配置,需要我们完成各种配置、参数匹配后的业务处理流程,类型下面这样:
if( commandLine.hasOption("help") ){helper.printHelp("calendar [options] nnwhere options include:", null, options, null, false);return;}if( commandLine.hasOption("version") ){printResult("1.0.0");return;}解析的过程有时候会比较些复杂,示例中是针对单一选项的分支,当多个选项混合使用时,比如tar -zxvf xxx.tar.gz这样的,当然前提是我们定义的CLI支持这种风格 。
示例下面通过一个简单的示例看下如何构建一个CLI的工具:该示例的作用是按指定格式输出当前日期:
clendar -o yyyy-MM-dd
  • 定义配置项
 private static Options initOptions() {Options options = new Options();options.addOption(Option.builder("H").longOpt("help").desc("show help information").build());options.addOption(Option.builder("V").longOpt("version").desc("show help information").build());options.addOption(Option.builder("O").longOpt("out").hasArg(true).argName("fmt") // 只是定义.required(false).desc("configure the date output format").build());return options;}
  • 解析参数
 private static CommandLine parseArguments(Options options, String[] args){CommandLineParser parser = new DefaultParser();try {return parser.parse(options, args);} catch (ParseException e) {System.err.println(e.getMessage());}return null;}
  • 询问阶段
private static void handleCommand(Options options, CommandLine commandLine) {if(ArrayUtils.isEmpty(commandLine.getOptions()) ){printResult("Please specify options for calendar building or use --help for more info.");return;}if( commandLine.hasOption("help") ){helper.printHelp("calendar [options] nnwhere options include:", null, options, null, false);return;}if( commandLine.hasOption("version") ){printResult("1.0.0");return;}if( commandLine.hasOption("out") ){String fmt = commandLine.getOptionValue("out");if(StringUtils.isEmpty(fmt)){fmt = "yyyy-MM-dd HH:mm:ss";}printResult(DateFormatUtils.format(new Date(), fmt));return;}// calendar: 'x' is not a git command. See 'calendar --help'.helper.printHelp(String.format("calendar: '%s' is not a calendar command. See 'calendar --help'.", Arrays.toString(commandLine.getArgs())), options, false);}定义程序入口:
public static void main(String[] args) {// 定义阶段Options options = initOptions();// 解析阶段CommandLine commandLine = parseArguments(options, args);// 询问阶段handleCommand(options, commandLine);}打包这里我们引入maven-assembly-plugin插件,主要帮助在打包时将依赖包一并写入jar文件,同时将入口文件定义到manifest:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.3.0</version><executions><execution><id>package-jar-with-dependencies</id><phase>package</phase><goals><goal>single</goal></goals><configuration><archive><manifest><mainClass>${main-class}</mainClass></manifest></archive><descriptorRefs><!-- bin,jar-with-dependencies,src,project --><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration></execution></executions></plugin>可以直接通过maven插件或者下的命令,将上面的代码打包成jar文件
mvn clean package测试jar如果安装上面的配置 , 最终会在项目target目录输出一个以jar-with-dependencies为后缀的jar文件,通过下面的命令可以测试cli命令
java -jar ./target/calendar-jar-with-dependencies.jar -h这样的CLI可不是我们想要的,一来需要依赖JRE的运行环境 , 同时调用极其不方便 。


推荐阅读