使用说明

Jdk-Plus2022年1月7日
大约 5 分钟

drawing

Cli-Plus - 使用Java编写命令行指令

Cli-Plus是一款开源的使用Java编写命令行指令的框架,它具有简单、高效、易用等特点,可以提高团队的工作效率。

说明

这是一款使用java编写命令行指令集的框架。

如何引入

<dependency>
    <groupId>plus.jdk</groupId>
    <artifactId>cli-plus</artifactId>
    <version>1.1.5</version>
</dependency>

一些有趣的组件

通过代码执行查看效果

(base) ➜  cli-plus git:(master) ✗ mvn -Dtest=plus.jdk.cli.weight.ProgressBarTest#testProgressBar test -q
Processing [========================================>] 100% 128/128
(base) ➜  cli-plus git:(master) ✗ mvn -Dtest=plus.jdk.cli.weight.TablePrinterTest#printTable test  -q
+----+----------------+------+--------+
| id | 姓名           | 年龄 | 性别   |
+----+----------------+------+--------+
| 1  | 张三💅         | 30   ||
| 2  | 李四           | 89   ||
| 3  | 王老五         | 30   | 男👵👲 |
| 4  | chang kai shen | 30   ||
| 4  | p-moon ☺️☺️    | 30   | 纯爷们 |
+----+----------------+------+--------+

定义指令并指定参数

如何定义一个指令:

package plus.jdk.cli.command;

import plus.jdk.cli.JCommandLinePlus;
import plus.jdk.cli.annotation.CommandLinePlus;
import plus.jdk.cli.annotation.CommandParameter;
import plus.jdk.cli.annotation.SubInstruction;

import java.util.List;
import java.util.Set;

@CommandLinePlus(description = "这是一个测试指令")
public class TestJCommand extends JCommandLinePlus {

    /**
     * 你可以使用required参数指定该项必须输入, 调用已经实现的validate() 函数去对参数做出校验
     */
    @CommandParameter(name = "u", longName = "uid", needArgs = true, description = "用户id", required = true)
    private Long uid;

    @CommandParameter(name = "p", longName = "phone", needArgs = true, description = "用户手机号")
    private String phone;

    /**
     * 对于简单类型,你可以使用, -<name> 或 --<longName> 指定参数,例如:-e xxx@jdk.plus, 或 --email xxx@jdk.plus
     */
    @CommandParameter(name = "e", longName = "email", needArgs = true, description = "用户邮箱")
    private String email;

    /**
     * 你可以使用多个选项来指定列表,例如 : -d d1 -d d2 --data d3
     */
    @CommandParameter(name = "d", longName = "data", needArgs = true, description = "参数列表")
    private List<String> dataList;

    /**
     * 你可以使用多个选项来指定列表,例如 : -d d1 -d d2 --data d3
     */
    @CommandParameter(name = "s", longName = "set", needArgs = true, description = "参数集合")
    private Set<String> dataSet;

    /**
     * 针对不需要参数的选项,你可以使用Boolean类型来接收,例如指定 -h 或 --help, 该值会被赋值为true,否则为false
     */
    @CommandParameter(name = "h", longName = "help", needArgs = false, description = "展示帮助信息")
    private Boolean help;

    /**
     * 可以使用 @SubInstruction 注解来定义子指令, 但凡指令中指定了要求执行子指令,那么将直接执行子指令中的逻辑,不再执行当前指令中的任务
     */
    @SubInstruction
    @CommandParameter(name = "sub", longName = "subInstruction", needArgs = false, description = "子指令")
    private TestSubInstruction subInstruction;

    @Override
    public void doInCommand() throws Exception {
        if(help) { // 若指定 -h 或 --help 选项,则展示帮助信息
            showUsage();
            return;
        }
        validate();
        // to do something according to Input parameters
        // which has been assigned to a member variable
    }

    public static void main(String[] args) throws Exception {
        TestJCommand testCommand = new TestJCommand();
        testCommand.run(args);
    }
}

执行

java -jar xxx.jar -u 123567 -p "p2data ss" --email xxx@jdk.plus -h -s s1 -s s2 --set s3 -d d1 -d d2 --data d3

** 按照上文所述的参数传递,执行的效果如下 **

配置文件

你需要在你的工程resources目录下指定cli-plus.properties

plus.jdk.help.header.welcome=Welcome to use cli-plus
plus.jdk.help.header.description=The command options are described below:
plus.jdk.help.footer.description=usage: xxx-tool -cn xx -e "ls /root"
plus.jdk.help.footer.contact=mail: moon@jdk.plus

生成指令帮助信息

调用封装好的showUsage方法可以生成帮助信息并打印,示例如下:

指令shell封装

#!/bin/bash

# 指定运行时的JAVA_HOME
#JAVA_HOME=${HOME}/.biz-tools/java-se-8u41-ri
#PATH=${JAVA_HOME}/bin:$PATH

if ! which java > /dev/null ; then
    echo "jdk 未安装, 请安装1.8以上版本"
    exit
fi

JAVA_VERSION=$(java -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}')

if [[ ! "${JAVA_VERSION}" =~ ^1.8.0.* ]]; then
    echo "jdk版本必须大于等于1.8,请检查环境配置"
    exit
fi

TOOLS_JAR=$(dirname "$0")/tools.jar

# shellcheck disable=SC2046
java -jar "${TOOLS_JAR}" "$@" -c $(dirname "$0")/conf/config.properties

配置的读取

我们封装了initializationConfig函数来帮你读取配置,该函数可以配合PropertiesValue注解使用,将配置内容转为实体类的配置。

定义实体类

package plus.jdk.cli.model;

import lombok.Data;
import plus.jdk.cli.annotation.PropertiesValue;

@Data
public class CliHelpModel {

    /**
     * header欢迎使用的标题
     */
    @PropertiesValue("plus.jdk.help.header.welcome")
    private String headerWelcome;

    /**
     * 想要展示的banner信息,你可以使用 resource 和 path参数指定要输出的banner位置
     */
    @PropertiesValue(value = "plus.jdk.help.header.banner", resource = true, path = "banner/banner.txt")
    private String banner;

    /**
     * header描述信息
     */
    @PropertiesValue("plus.jdk.help.header.description")
    private String headerDesc;

    /**
     * 底部描述信息
     */
    @PropertiesValue("plus.jdk.help.footer.description")
    private String footerDesc;

    /**
     * 联系信息
     */
    @PropertiesValue("plus.jdk.help.footer.contact")
    private String footerContact;
}

读取配置:

import static plus.jdk.cli.common.PropertiesUtil.initializationConfig;
//...
CliHelpModel cliHelpModel = initializationConfig(CliHelpModel.class, "cli-plus.properties", true);
//...

添加对特殊类型的支持

如果你的输入参数需要指定一些自定义类型(目前仅支持 BooleanLongStringInteger四种)。

自定义自己的类型适配器

你可以通过实现ITypeAdapter接口来自定义相关序列化的功能。示例如下,下面是一个关于Long类型序列化实现的示例:

package plus.jdk.cli.type.adapter;

import com.google.gson.TypeAdapter;

public class LongTypeAdapter implements ITypeAdapter<Long> {
    @Override
    public Long deserialize(String dataStr) {
        if(dataStr == null) {
            return null;
        }
        return Long.parseLong(dataStr);
    }

    @Override
    public String serialize(Long data) {
        if(data == null) {
            return null;
        }
        return String.valueOf(data);
    }
}

注册实现的适配器

@CommandLinePlus(description = "这是一个测试指令")
public class TestJCommand extends JCommandLinePlus {

    // ...

    public static void main(String[] args) throws Exception {
        TestJCommand testCommand = new TestJCommand();
        // 在完成调用前注册自己实现的适配器组件
        Options.registerTypeAdapter(Long.class, new LongTypeAdapter());
        testCommand.run(args);
    }
}
Loading...