Spring Shell 是 Spring 生态中的一员,用于开发命令行应用程序

 

添加 jar 包依赖

<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell-starter</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>

 

内置命令

shell:>help
AVAILABLE COMMANDS

Built-In Commands
# 清空命令行界面
clear: Clear the shell screen.
# 退出应用
exit, quit: Exit the shell.
# 显示帮助信息
help: Display help about available commands.
# 从文件中读取并执行批量命令
script: Read and execute commands from a file.
# 报错时读取异常堆栈信息
stacktrace: Display the full stacktrace of the last error.

 

ShellMethod 注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface ShellMethod {
String INHERITED = "";
// 设置命令名称
String[] key() default {};
// 设置命名描述
String value() default "";
// 设置命令参数前缀,默认为“--”
String prefix() default "--";
// 设置命令分组
String group() default "";
}

 

系统任务列表

shell:>shell:>help
AVAILABLE COMMANDS

Built-In Commands
clear: Clear the shell screen.
exit, quit: Exit the shell.
help: Display help about available commands.
script: Read and execute commands from a file.
stacktrace: Display the full stacktrace of the last error.

# 命令所属组名
calculate
# 具体的命令
addition, sum: 加法运算
division: 除法运算
multiplication: 乘法运算
subtraction: 加法运算

expand
defaultValue: 设置参数默认值
multiAdd: 5个数相加
multiSum: 5个数加法运算
startup: 启动服务

fileOpt
# download 和 upload 命令的执行都需要依赖指定状态(命令前带 *)
* download: 下载文件
login: 登录
logout: 注销
* upload: 上传文件

Commands marked with (*) are currently unavailable.

 

代码演示

CalculateTask

@ShellComponent
@ShellCommandGroup("calculate")
@Slf4j
public class CalculateTask {

/**
* addition | sum 命令均可
* <ul>
* <li>
* shell:> addition 1 2
* </li>
* <li>
* shell:> addition --x 1 --y 2 使用带命令参数前缀的方式
* </li>
* <li>
* shell:> addition --y 1 --x 2
* </li>
* <li>
* shell:> sum --y 1 --x 2
* </li>
* </ul>
* */
@ShellMethod(key = {"addition", "sum"}, value = "加法运算")
private void addition(int x, int y) {
log.info("计算两数相加, x={}, y={}", x, y);
}



/**
* 使用属性 {@link ShellMethod#prefix()} 定义参数前缀
*
* <ul>
* <li>
* shell:> subtraction 1 2
* </li>
* <li>
* shell:> subtraction @x 2 @y 3
* </li>
* <li>
* shell:> subtraction @y 2 @x 3
* </li>
* </ul>
* */
@ShellMethod(key = "subtraction", value = "加法运算", prefix = "@")
private void subtraction(int x, int y) {
log.info("计算两数相减, x={}, y={}", x, y);
}



/**
* 使用注解 @ShellOption 对命令参数进行定制
*
* <ul>
* <li>
* shell:> multiplication 1 2
* </li>
* <li>
* shell:> multiplication -a 3 -b 5
* </li>
* <li>
* shell:> multiplication -b 3 -a 5
* </li>
* </ul>
* */
@ShellMethod(key = "multiplication", value = "乘法运算")
private void multiplication(@ShellOption("-a") int x, @ShellOption("-b") int y) {
log.info("计算两数相乘, x={}, y={}", x, y);
}



/**
* 使用注解 @ShellOption 为命令参数指定多个名称
*
* <ul>
* <li>
* shell:> division 3 5
* </li>
* <li>
* shell:> division -m 3 @n 5
* </li>
* <li>
* shell:> division @m 3 @n 5
* </li>
* <li>
* shell:> division @m 3 -n
* </li>
* </ul>
* */
@ShellMethod(key = "division", value = "除法运算")
private void division(@ShellOption({"@m", "-m"}) int x, @ShellOption({"@n", "-n"}) int y) {
log.info("计算两数相除, x={}, y={}", x, y);
}

}

 

ExpandTask

@ShellComponent
@ShellCommandGroup("expand")
@Slf4j
public class ExpandTask {

/**
* 对于布尔类型的参数, 默认值为 false, 当明确传递参数名时, 值为 true
*
* <blockquote>
* 对于布尔参数值处理比较特别,无需像普通参数一样传递参数值,否则报错
* </blockquote>
*
* <ul>
* <li>
* shell:> startup
* </li>
* <li>
* shell:> startup --startup
* </li>
* </ul>
* */
@ShellMethod(key = "startup", value = "启动服务")
private String startup(boolean startup) {
log.info("startup={}.", startup);
return "AnswerAIL";
}



/**
* 为一个参数传递多个值(数组), 可以使用注解 @ShellOption 的属性 arity 指定参数值的个数
*
* <ul>
* <li>
* shell:> multiAdd 1 2 3 4 5
* </li>
* <li>
* shell:> multiAdd --nums 1 2 3 4 5
* </li>
* </ul>
* */
@ShellMethod(key = "multiAdd", value = "5个数相加")
private int multiAdd(@ShellOption(arity = 5) int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}



/**
* 为一个参数传递多个值(数组), 可以使用注解 @ShellOption 的属性 arity 指定参数值的个数
*
* <blockquote>
* 注意: arity = 5 传递的参数个数必须是 5 个
* </blockquote>
*
* <ul>
* <li>
* shell:> multiSum 1 2 3 4 5
* </li>
* <li>
* shell:> multiSum --nums 1 2 3 4 5
* </li>
* </ul>
* */
@ShellMethod(key = "multiSum", value = "5个数加法运算")
private int multiSum(@ShellOption(arity = 5) List<Integer> nums) {
AtomicInteger sum = new AtomicInteger(0);
nums.forEach(sum::addAndGet);
return sum.get();
}



/**
* 使用注解 @ShellOption 通过属性 defaultValue 为参数指定默认值
*
* <ul>
* <li>
* shell:> defaultValue
* </li>
* <li>
* shell:> defaultValue answer
* </li>
* <li>
* shell:> defaultValue --name answer
* </li>
* </ul>
* */
@ShellMethod(key = "defaultValue", value = "设置参数默认值")
private void defaultValue(@ShellOption(defaultValue = "AnswerAIL") String name) {
log.info("name={}.", name);
}

}

 

FileOptTask - 命令动态可用性

@ShellComponent
@ShellCommandGroup("fileOpt")
@Slf4j
public class FileOptTask {
private boolean logined = false;



@ShellMethod(key = "login", value = "登录")
public void login() {
log.info("登录成功");
logined = true;
}

@ShellMethod(key = "logout", value = "注销")
public void logout() {
log.info("注销成功");
logined = false;
}



@ShellMethod(key = {"upload"}, value = "上传文件")
// @ShellMethodAvailability({"chkLogined"}) // 2
private void uploadFile() {
log.info("upload file...");
}



@ShellMethod(key = {"download"}, value = "下载文件")
// @ShellMethodAvailability({"chkLogined"}) // 2
private void downloadFile() {
log.info("download file...");
}



@ShellMethodAvailability({"download", "upload"}) // 1
public Availability chkLogined() {
return logined ? Availability.available():Availability.unavailable("you are not login");
}

}

 

命令动态可用性小结

  • 使用了动态命令可用性的命令会在交互界面中显示一个星号提示, 明确提示该命令的执行需要依赖指定状态(通常是其他命令的执行结果)
  • 不论如何, 提供动态命令可用性的方法返回值必须是 org.springframework.shell.Availability 类型对象

 

停止服务

@Slf4j
@ShellComponent
public class ExitTask {

@ShellMethod(key = "exitTask", value = "退出任务")
public void exitTask() {
log.info("服务停止运行~");
System.exit(0);
}
}

 

服务运行脚本

#!/bin/bash

[ $1 ] && datekey=$1 || datekey=$(date -d -1day +'%Y%m%d')
echo "`date "+%Y-%m-%d %H:%M:%S"` datekey=[${datekey}], length=${#datekey}"

if grep -qv '^[[:digit:]]*$' <<< "${datekey}"; then
echo "`date "+%Y-%m-%d %H:%M:%S"` 日期格式非数字, 格式=yyyyMMdd"
exit 1
fi

if [ ${#datekey} != 8 ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` 日期格式错误, 格式=yyyyMMdd"
exit 1;
fi

# 需要引入环境配置
source ~/.bash_profile
sd_context_path="/home/answer/spring-shell"
jar_name="shell-demo-1.0.jar"
env_active="prod"

echo "`date "+%Y-%m-%d %H:%M:%S"` 准备跑日期=${datekey} 任务"

java -jar ${sd_context_path}/${jar_name} --spring.profiles.active=${env_active} >> ${sd_context_path}/sd_out.log <<EOF
dailyTask ${datekey}
exitTask
EOF

echo "`date "+%Y-%m-%d %H:%M:%S"` datekey=[${datekey}] 任务完成~ status=$?"
echo
echo

Reference