使用Spring Shell 快速开发自己的命令交互窗口

强颜欢笑 提交于 2020-08-15 21:52:43

Spring Shell

有时候,为了方便开发和测试服务器,并不需要一个漂亮的用户界面,使用一个简单的命令窗口即可。如下所示: 交互式命令窗口

这里介绍一个快速,方便,易用,简单的交互式命令窗口开发组件-Spring Shell 没错,又是spring 生态中的。

源码地址

https://gitee.com/wgslucky/spring-shell-demo

创建项目

本项目是使用Eclipse作为开发的IDE,同样,直接导入到Idea之中也可以使用。使用的JDK需要是1.8或更高的版本,我测试过在JDK11上也可以使用。 在eclipse中创建maven项目:spring-shell-demo,然后在pom.xml中添加如下依赖:

   <parent>
	    <!-- 添加spring boot 父pom依赖,这个不能少,spring shell官方的文档中没有写 -->
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.shell</groupId>
			<artifactId>spring-shell-starter</artifactId>
			<version>2.0.0.RELEASE</version>
		</dependency>
	</dependencies>

添加启动类

@SpringBootApplication
public class SpringShellDemo {

	public static void main(String[] args) {
		SpringApplication app = new SpringApplication(SpringShellDemo.class);
		app.setBannerMode(Mode.OFF);
		app.setWebApplicationType(WebApplicationType.NONE);
		app.run(args);
	}
}

到此,项目创建完成。下面就是见证奇迹的时候了。

快速添加一条命令

创建一个命令类,类名可以自定义:

@ShellComponent
public class MyCommand {
	@ShellMethod("连接服务器,格式:connect ip port")
	public String connect(String ip,int port) {
		return String.format("连接服务成功:%s:%s", ip,port);
	}
}

然后,运行项目的启动类main方法,在控制台就可以输入命令了: 输入命令 就是这么简单!!!,只需要两步:

  1. 在命令类上面添加注解:@ShellComponent
  2. 在方法上面添加注解:@ShellMethod

项目打包和运行

在项目的pom.xml所在的目录上执行

mvn clean package

然后在target的目录下面生成了运行包:spring-shell-demo-0.0.1-SNAPSHOT.jar 使用下面的命令可以直接运行此包:

java -jar spring-shell-demo-0.0.1-SNAPSHOT.jar

这样就可以在IDE外面随时使用了。

使用小技巧

现在已经可以轻松的添加自己想要的交互命令了,交互命令的最重要的职责就是接收用户输入的参数,剩下如何执行命令就是自己的业务逻辑了。下面介绍一些使用小技巧。

内置命令

Spring Shell内容了一些常用的命令,可以直接使用,可以在运行的命令窗口中输入help,快速查看这些命令:

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注解中添加对此命令的描述,这样在使用help命令时,就可以看到这些描述,明白命令如何使用,如上面的第一个命令的例子,在命令窗口中输入help可以看到:

My Command
       connect: 连接服务器,格式:connect ip port

自定义命令的名字

默认情况下是不需要自定义命令的名字的,它会使用执行这个命令的方法名转化相应的窗口命令名字,如果是多个单词,使用-分开。比如connect方法,它的命令名字就是connect,如果方法名是sayHello,那么它的命令名字就是:say-hello 如果想要自定义命令名字,可以在@ShellMethod注解中添加:

	@ShellMethod(value = "登陆服务器,格式:login-server playerId",key = "login-server")
	public String login(String playerId) {
		return "登陆成功:" + playerId;
	}

修改提示符

在spring shell运行时,默认的命令提示符是:shell:> 有时候,看着别扭,如果能修改为自定义的提示符就好。这个可以修改,需要添加一个新的类:

@Service
public class CustomPromptProvider implements PromptProvider{

	@Override
	public AttributedString getPrompt() {
		return new AttributedString("xinyues-client:>");
	}

}

这样重新打包运行,输入的命令提示符就变成了 xinyues-client:>

带参数名输入命令参数

在输入命令时,如果不使用命令参数名字,那么参数的顺序必须和方法中定义的参数顺序一致。如果想使顺序不同,可以添加参数名称,如下所示:

xinyues-client:>connect --port 8888  --ip localhost
连接服务成功:localhost:8888
xinyues-client:>

参数需要两个横扛(--)。

添加默认参数值

有时候,一些命令可以简化一下,如果不输入参数的话,就使用参数的默认值。如下所示:

	@ShellMethod("连接服务器,格式:connect ip port")
	public String connectDefault(@ShellOption(defaultValue = 
"localhost")String ip,@ShellOption(defaultValue = "8080")int port) {
		return String.format("连接服务成功:%s:%s", ip,port);
	}

在参数上面使用了一个新的注解:@ShellOption 使用命令时可以直接输入命令名,而不需要输入参数:

xinyues-client:>connect-default
连接服务成功:localhost:8080
xinyues-client:>

使用数组参数

有时候,为了输入方便,不想定义太多的参数变量,或者参数是一个数组数据时,可以使用下面这种方式:

        @ShellMethod("Add Numbers.")
        public float add(@ShellOption(arity=3) float[] numbers) {
                return numbers[0] + numbers[1] + numbers[2];
        }

输入的参数带空格时

默认情况下,spring shell是以空格区分多个参数的,如果一个参数是多个单词,且有空格,就不能直接输入了,可以使用双引号或单引号,比如下面这个命令:

        @ShellMethod("Prints what has been entered.")
        public String echo(String what) {
                return "You said " + what;
        }

输入如下所示:

shell:>echo Hello
You said Hello
shell:>echo 'Hello'
You said Hello
shell:>echo 'Hello World'
You said Hello World
shell:>echo "Hello World"
You said Hello World

也可以这样使用,避免使用转义符:

shell:>echo "I'm here!"
You said I'm here!
shell:>echo 'He said "Hi!"'
You said He said "Hi!"

命令自动补全功能

可以使用tab键,自动补命令名字,和使用linux命令类似,也可以使用tab自动补全参数名字。

命令换行输入

有时候,命令参数太多,一行可能输入不完,可以在一行的末尾添加 \ ,然后另起一行输入命令:

shell:>register module --type source --name foo   
> --uri file:///tmp/bar
Successfully registered module 'source:foo'

快捷键使用

  1. ctrl + r 搜索输入过历史执行过的命令。减少重复的输入,提高操作效率。
  2. ctrl + a 跳转到行头输入
  3. ctrl + e 跳转到行尾输入
  4. 上下箭头 输入完命令名字之后,按上下箭头可以查阅之前输入过的参数命令。

参数限制

可以使用注解,对参数进入限制,防止用户输入错误,如下所示:

        @ShellMethod("Change password.")
        public String changePassword(@Size(min = 8, max = 40) String password) {
                return "Password successfully set to " + password;
        }

如果输入的不符合要求,会有提示:

shell:>change-password hello
The following constraints were not met:
	--password string : size must be between 8 and 40 (You passed 'hello')

更多可以使用的注解,请参阅:https://beanvalidation.org/2.0/spec/#builtinconstraints

命令有效性检测

有时候,多个命令之间可能有某种依赖性,比如这样一个场景,客户端有一个下载download命令,但是在使用下载命令的时候,必须先connect成功。可以这样检测download命令是否可用:

@ShellComponent
public class MyCommands {

    private boolean connected;

    @ShellMethod("Connect to the server.")
    public void connect(String user, String password) {
        [...]
        connected = true;
    }

    @ShellMethod("Download the nuclear codes.")
    public void download() {
        [...]
    }
   // 注意,这里方法的命名是命令名 + Availability
    public Availability downloadAvailability() {
        return connected
            ? Availability.available()
            : Availability.unavailable("you are not connected");
    }
}

这样,如果用户没有使用connect命令,而直接使用download命令,就会提示:

xinyues-client:>download
[31mCommand 'download' exists but is not currently available because you are not connected[0m
[31mDetails of the error have been omitted. You can use the [1mstacktrace[22m command to print the full stacktrace.[0m
xinyues-client:>

上面这个检测方法是命名是有规则的必须是命令名 + Availability;另一种方式是使用注解指定检测的方法名:

    @ShellMethod("Download the nuclear codes.")
    @ShellMethodAvailability("availabilityCheck") 
    public void download() {
        [...]
    }

    public Availability availabilityCheck() { 
        return connected
            ? Availability.available()
            : Availability.unavailable("you are not connected");
    }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!