Apache Commons CLI 入门教程:轻松解析命令行参数
一、什么是 Commons CLI?
Apache Commons CLI 是一个简单易用的 Java 库,专门用于解析命令行参数。当我们需要开发命令行工具或应用程序时,它可以帮助我们:
- 定义程序接受的参数格式
- 自动解析用户输入的命令行参数
- 生成标准化的帮助信息
- 验证参数的正确性
二、为什么选择 Commons CLI?
相比自己编写参数解析逻辑,使用 Commons CLI 有以下优势:
- 标准化:遵循 Unix/Linux 命令行工具的标准惯例
- 功能完善:支持长短选项、必选/可选参数、参数分组等
- 易用性:API 设计直观,学习曲线平缓
- 健壮性:经过广泛测试,能处理各种边界情况
三、快速开始
1. 添加依赖
首先需要在项目中添加 Commons CLI 的依赖:
Maven 项目:
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.9.0</version>
</dependency>
Gradle 项目:
implementation 'commons-cli:commons-cli:1.9.0'
上述依赖中的版本号
1.9.0
是当前最新版本,以下代码均以当前版本为准。如果您需要在生产环境使用,请及时更新为最新版本。
2. 基础示例
让我们从一个最简单的例子开始:
package org.hbin.cli;
import org.apache.commons.cli.*;
public class GreetApp {
public static void main(String[] args) {
// 1. 创建选项定义
Options options = new Options();
options.addOption("n", "name", true, "指定您的名字");
// 2. 创建解析器
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
try {
// 3. 解析参数
CommandLine cmd = parser.parse(options, args);
// 4. 处理参数
if (cmd.hasOption("n")) {
String name = cmd.getOptionValue("n");
System.out.println("你好, " + name + "!");
} else {
System.out.println("你好, 世界!");
}
} catch (ParseException e) {
System.err.println("参数错误: " + e.getMessage());
formatter.printHelp("greet", options);
System.exit(1);
}
}
}
3. 运行示例
1. 在Idea中运行
2. 命令行中运行
> java org.hbin.cli.GreetApp -n Haley
注意,直接运行上述命令可能会报错 java.lang.NoClassDefFoundError
,如下图:
这是因为运行时classpath中缺少Commons CLI的jar文件,需要指定其路径。
> java -cp .;%MAVEN_HOME%\repo\commons-cli\commons-cli\1.9.0\commons-cli-1.9.0.jar org.hbin.cli.GreetApp -n Haley
3. 使用 Maven/Gradle 运行(推荐)
如果是Maven项目:
mvn compile exec:java -Dexec.mainClass="org.hbin.cli.GreetApp" -Dexec.args="-n Haley"
如果是Gradle项目:
gradle run --args="-n Haley"
4. 使用可运行jar运行
上述代码也可以使用Maven Assembly Plugin制作成一个可运行jar,然后再运行。步骤如下:
1. 配置pom.xml
<build>
<plugins>
<!-- 配置 maven-assembly-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<!-- 指定主类 -->
<mainClass>org.hbin.cli.GreetApp</mainClass>
</manifest>
</archive>
<descriptorRefs>
<!-- 使用预定义的 jar-with-dependencies 描述符 -->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2. 执行打包任务
双击 maven 面板中的 package 执行打包或使用命令行打包:mvn clean package
。
3. 查看生成的jar文件
打包完成后,在项目的 target 目录下会生成两个 Jar 文件:
- CliExample-1.0-SNAPSHOT.jar - 不包含依赖的基本 Jar
- CliExample-1.0-SNAPSHOT-jar-with-dependencies.jar - 包含所有依赖的可运行 Jar
4. 运行jar文件
java -jar target/CliExample-1.0-SNAPSHOT-jar-with-dependencies.jar -n Haley
四、核心概念详解
1. 选项定义
Commons CLI 使用 Options
类来定义程序接受的参数:
Options options = new Options();
// 简单选项
options.addOption("h", "help", false, "显示帮助信息");
// 带参数的选项
options.addOption("n", "name", true, "指定输入名称");
// 使用构建器模式创建复杂选项
options.addOption(Option.builder("n")
.longOpt("name")
.hasArg()
.argName("NAME")
.desc("指定名称")
.build());
2. 选项类型
类型 | 示例 | 说明 |
---|---|---|
无参选项 | -h , --help |
只表示一个开关状态 |
带参选项 | -n Haley |
需要接收一个参数 |
可选参数 | -d [debugLevel] |
参数可有可无 |
多值选项 | -Dkey1=value1 -Dkey2=value2 |
可以接收多个键值对 |
3. 参数解析
使用 DefaultParser
解析命令行参数:
CommandLineParser parser = new DefaultParser();
try {
CommandLine cmd = parser.parse(options, args);
// 检查选项是否存在
if (cmd.hasOption("h")) {
// 处理帮助选项
}
// 获取选项值
String name = cmd.getOptionValue("n");
} catch (ParseException e) {
// 处理解析错误
}
4. 帮助信息
HelpFormatter
可以生成标准化的帮助信息:
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("greet", options, true);
输出示例:
五、实战案例
1. 文件处理工具
package org.hbin.cli;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
public class FileProcessor {
public static void main(String[] args) {
Options options = new Options();
// 必选输入文件
options.addOption(Option.builder("i")
.longOpt("input")
.required()
.hasArg()
.desc("输入文件路径(必选)")
.build());
// 可选输出文件
options.addOption(Option.builder("o")
.longOpt("output")
.hasArg()
.desc("输出文件路径")
.build());
// 详细模式
options.addOption("v", "verbose", false, "显示详细日志");
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
try {
CommandLine cmd = parser.parse(options, args);
String inputFile = cmd.getOptionValue("i");
System.out.println("处理文件: " + inputFile);
if (cmd.hasOption("o")) {
String outputFile = cmd.getOptionValue("o");
System.out.println("输出到: " + outputFile);
}
if (cmd.hasOption("v")) {
System.out.println("详细模式已启用");
}
// 实际文件处理逻辑...
} catch (ParseException e) {
System.err.println("错误: " + e.getMessage());
formatter.printHelp("fileprocessor", options, true);
System.exit(1);
}
}
}
2. 配置加载工具
package org.hbin.cli;
import java.util.Properties;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
public class ConfigLoader {
public static void main(String[] args) {
Options options = new Options();
// 配置文件选项
options.addOption("c", "config", true, "配置文件路径");
// 多值系统属性
options.addOption(Option.builder("D")
.hasArgs()
.valueSeparator()
.desc("系统属性,格式为-Dkey=value")
.build());
try {
CommandLine cmd = new DefaultParser().parse(options, args);
if (cmd.hasOption("c")) {
String configFile = cmd.getOptionValue("c");
System.out.println("加载配置文件: " + configFile);
}
if (cmd.hasOption("D")) {
Properties props = cmd.getOptionProperties("D");
System.out.println("系统属性:");
props.forEach((k, v) -> System.out.println(" " + k + " = " + v));
}
} catch (ParseException e) {
new HelpFormatter().printHelp("configloader", options);
System.exit(1);
}
}
}
六、最佳实践
- 必选参数检查:使用
required(true)
标记必选参数 - 友好的帮助信息:为每个选项提供清晰的描述
- 参数验证:解析后应对参数值进行额外验证
- 错误处理:捕获
ParseException
并提供有用的错误信息 - 代码组织:将选项定义、解析和处理逻辑分开
七、常见问题解答
Q1: 如何处理未知选项?
A: DefaultParser
默认会抛出 ParseException
,你可以在 catch 块中处理这种情况。
Q2: 如何支持子命令?
A: Commons CLI 本身不直接支持子命令,但可以通过组合多个 Options
对象来实现类似功能。
Q3: 如何设置选项的默认值?
A: 可以在获取选项值时提供默认值:
String value = cmd.getOptionValue("option", "default");
Q4: 如何处理多个相同的选项?
A: 使用 getOptionValues()
方法:
String[] values = cmd.getOptionValues("option");
八、总结
通过本教程,你已经学会了:
- 如何在项目中引入 Commons CLI
- 如何定义各种类型的命令行选项
- 如何解析和处理命令行参数
- 如何生成标准化的帮助信息
- 几个实用的实战案例
Commons CLI 是 Java 开发命令行工具的利器,掌握它能让你快速构建出专业级的命令行应用。现在,尝试为你自己的项目添加命令行支持吧!