MeteorCat / JCommander命令行部署

Created Sat, 03 May 2025 15:44:03 +0800 Modified Wed, 29 Oct 2025 23:24:53 +0800
1189 Words

在日常当中对于常规使用 Web 项目都会集成 SpringBoot 工具, 一般来说直接按照以下方式启动就行:

# 启动 Jar 并携带启动配置文件
java -jar package.jar -Dspring.config.location=./application.yml

实际上其他简单和非Web应用并不需要集成这么重量级框架, 所以应该回归到传统附带启动参数的方法, 采用第三方库 JCommander 就能直接编写简单高效的命令行启动工具.

建议: 命令行最好全部采用英语而不要用中文emoji等特殊字符说明, 有的环境会因为缺少字符集乱码(英语最通用所以基本默认集成)

按照官方需要引入第三方库:

<!-- JCommander 第三方库 -->
<dependency>
    <groupId>org.jcommander</groupId>
    <artifactId>jcommander</artifactId>
    <version>2.0</version>
</dependency>

这里推荐还需要设置打包工具, 让其打包的时候指定 main 入口类, 避免启动的时候无法找到入口类:

<!-- Maven打包配置 -->
<build>
    <plugins>

        <!-- 编译打包配置 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.13.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <!-- Jar打包功能配置 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.4.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <!-- 这里就是默认启动的入口类文件 com.fusion.game.FusionHttpApplication.java -->
                        <mainClass>com.fusion.game.FusionHttpApplication</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

这样基本安装配置就引入完成, 之后就是定义命令行工具的参数配置; 首先就是假设我们需要定义 静态Web 服务启动, 而 Web 服务需要以下参数来启动:

  • -l|--listen: 监听地址, 默认为 127.0.0.1
  • -p|--port: 监听端口, 默认为 8080
  • -d|--dir: Web服务映射的本地目录, 必须设置该参数
  • -h|--help: 默认展示帮助信息(bool)
  • -v|--version: 默认展示版本信息(bool)

JCommander 支持简单的单独参数配置, 但还是推荐采用结构体定义规则之后参数验证单独管理比较好

这就是最基础的静态应用启动参数, 这里定义:

package com.fusion.game;

import com.beust.jcommander.Parameter;


/**
 * 自定义的应用参数结构, 这里节约时间没有采用 Set|Get 处理
 */
public class FusionWebArgs {

    /**
     * 监听地址
     */
    @Parameter(names = {"-l", "--listen"}, description = "Listen address")
    String listen = "127.0.0.1";

    /**
     * 监听端口
     */
    @Parameter(names = {"-p", "--port"}, description = "Listen port")
    Integer port = 8080;

    /**
     * 映射目录
     */
    @Parameter(names = {"-d", "--dir"}, description = "Local directory")
    String directory = "";


    /**
     * 打印帮助内容
     */
    @Parameter(names = {"-h", "--help"}, description = "print help info")
    boolean help = false;

    /**
     * 打印版本信息
     */
    @Parameter(names = {"-v", "--version"}, description = "print version info")
    boolean version = false;

}

之后就是在入口类调用验证器过滤:

package com.fusion.game;

/**
 * 应用入口
 */
public class FusionHttpApplication {

    /**
     * 入口方法
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        // 规则生成并且解析
        var rule = new FusionWebArgs();
        var commander = JCommander
                .newBuilder()
                .addObject(rule)
                .build();
        commander.parse(args);

        // 验证参数时候正确, help直接跳过
        if (rule.help) {
            commander.usage();
            return; // 直接弹出
        }

        // 打印版本内容不做后续处理
        if (rule.version) {
            System.out.println("v1.1.1");
            return;
        }

        // 确认目录有配置
        if (rule.directory.isBlank()) {
            commander.usage();
            return;
        }

        // 确定目录存在
        Path path = Paths.get(rule.directory);
        if (!Files.exists(path)) {
            System.err.println("Not found directory: " + rule.directory);
            return;
        }

        System.out.printf("创建服务器完成 -> %s:%d  <--> %s%n", rule.listen, rule.port, rule.directory);
    }
}

不过为了高内聚的情况, 可以把验证放到结构体并弹出 `` 来确认最后验证完成:

// 这里修改参数结构体, 追加验证方法
public class FusionWebArgs {
    /**
     * 验证参数
     *
     * @return boolean
     * @throws RuntimeException 验证异常
     */
    public boolean run(JCommander commander) throws RuntimeException {
        // 验证参数时候正确, help直接跳过
        if (help) {
            commander.usage();
            return false;
        }

        // 打印版本内容不做后续处理
        if (version) {
            System.out.println("v1.1.1");
            return false;
        }

        // 确认目录有配置
        if (directory.isBlank()) {
            commander.usage();
            return false;
        }

        // 确定目录存在
        Path path = Paths.get(directory);
        if (!Files.exists(path)) {
            throw new RuntimeException("Not found directory: " + directory);
        }

        return true;
    }
}

之后简单移交给内部就行了:

/**
 * 应用入口
 */
public class FusionHttpApplication {

    /**
     * 入口方法
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        // 规则生成并且解析
        var rule = new FusionWebArgs();
        var commander = JCommander
                .newBuilder()
                .addObject(rule)
                .build();
        commander.parse(args);

        // 直接移交给内部验证
        if (!rule.run(commander)) {
            return;
        }

        System.out.printf("创建服务器完成 -> %s:%d  <--> %s%n", rule.listen, rule.port, rule.directory);
    }
}

这样编译出命令行 Jar 包, 可以直接调用:

# 模拟传递参数就能调用运行
java -jar package.jar -d /tmp -l 192.168.1.1 -p 80