Spring Shell
有時候,為了方便開發(fā)和測試服務器蕊爵,并不需要一個漂亮的用戶界面辉哥,使用一個簡單的命令窗口即可。如下所示:
這里介紹一個快速攒射,方便醋旦,易用,簡單的交互式命令窗口開發(fā)組件-Spring Shell
沒錯会放,又是spring 生態(tài)中的浑度。
源碼地址
https://gitee.com/wgslucky/spring-shell-demo
創(chuàng)建項目
本項目是使用Eclipse作為開發(fā)的IDE,同樣鸦概,直接導入到Idea之中也可以使用箩张。使用的JDK需要是1.8或更高的版本甩骏,我測試過在JDK11上也可以使用。
在eclipse中創(chuàng)建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);
}
}
到此论熙,項目創(chuàng)建完成福青。下面就是見證奇跡的時候了。
快速添加一條命令
創(chuàng)建一個命令類脓诡,類名可以自定義:
@ShellComponent
public class MyCommand {
@ShellMethod("連接服務器无午,格式:connect ip port")
public String connect(String ip,int port) {
return String.format("連接服務成功:%s:%s", ip,port);
}
}
然后,運行項目的啟動類main方法祝谚,在控制臺就可以輸入命令了:
就是這么簡單O艹佟!交惯!次泽,只需要兩步:
- 在命令類上面添加注解:@ShellComponent
- 在方法上面添加注解:@ShellMethod
項目打包和運行
在項目的pom.xml所在的目錄上執(zhí)行
mvn clean package
然后在target的目錄下面生成了運行包:spring-shell-demo-0.0.1-SNAPSHOT.jar
使用下面的命令可以直接運行此包:
java -jar spring-shell-demo-0.0.1-SNAPSHOT.jar
這樣就可以在IDE外面隨時使用了。
使用小技巧
現(xiàn)在已經(jīng)可以輕松的添加自己想要的交互命令了席爽,交互命令的最重要的職責就是接收用戶輸入的參數(shù)意荤,剩下如何執(zhí)行命令就是自己的業(yè)務邏輯了。下面介紹一些使用小技巧玖像。
內(nèi)置命令
Spring Shell內(nèi)容了一些常用的命令齐饮,可以直接使用,可以在運行的命令窗口中輸入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. (從文件中讀取命令并執(zhí)行)
stacktrace: Display the full stacktrace of the last error.
(顯示異常棧陵像,一般遇到錯誤時寇壳,使用它快速查看異常棧)
添加命令描述
可以在@ShellMethod注解中添加對此命令的描述,這樣在使用help命令時泞歉,就可以看到這些描述,明白命令如何使用榛丢,如上面的第一個命令的例子挺庞,在命令窗口中輸入help可以看到:
My Command
connect: 連接服務器,格式:connect ip port
自定義命令的名字
默認情況下是不需要自定義命令的名字的掖鱼,它會使用執(zhí)行這個命令的方法名轉(zhuǎn)化相應的窗口命令名字援制,如果是多個單詞,使用-分開增拥。比如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:>
了
帶參數(shù)名輸入命令參數(shù)
在輸入命令時掰吕,如果不使用命令參數(shù)名字,那么參數(shù)的順序必須和方法中定義的參數(shù)順序一致局待。如果想使順序不同菱属,可以添加參數(shù)名稱,如下所示:
xinyues-client:>connect --port 8888 --ip localhost
連接服務成功:localhost:8888
xinyues-client:>
參數(shù)需要兩個橫扛(--)薛耻。
添加默認參數(shù)值
有時候赏陵,一些命令可以簡化一下,如果不輸入?yún)?shù)的話缕溉,就使用參數(shù)的默認值吃型。如下所示:
@ShellMethod("連接服務器,格式:connect ip port")
public String connectDefault(@ShellOption(defaultValue =
"localhost")String ip,@ShellOption(defaultValue = "8080")int port) {
return String.format("連接服務成功:%s:%s", ip,port);
}
在參數(shù)上面使用了一個新的注解:@ShellOption
使用命令時可以直接輸入命令名勤晚,而不需要輸入?yún)?shù):
xinyues-client:>connect-default
連接服務成功:localhost:8080
xinyues-client:>
使用數(shù)組參數(shù)
有時候,為了輸入方便鸟蜡,不想定義太多的參數(shù)變量挺邀,或者參數(shù)是一個數(shù)組數(shù)據(jù)時,可以使用下面這種方式:
@ShellMethod("Add Numbers.")
public float add(@ShellOption(arity=3) float[] numbers) {
return numbers[0] + numbers[1] + numbers[2];
}
輸入的參數(shù)帶空格時
默認情況下,spring shell是以空格區(qū)分多個參數(shù)的沦补,如果一個參數(shù)是多個單詞咪橙,且有空格虚倒,就不能直接輸入了魂奥,可以使用雙引號或單引號易猫,比如下面這個命令:
@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
也可以這樣使用,避免使用轉(zhuǎn)義符:
shell:>echo "I'm here!"
You said I'm here!
shell:>echo 'He said "Hi!"'
You said He said "Hi!"
命令自動補全功能
可以使用tab鍵哈蝇,自動補命令名字攘已,和使用linux命令類似,也可以使用tab自動補全參數(shù)名字吠勘。
命令換行輸入
有時候峡眶,命令參數(shù)太多,一行可能輸入不完诵姜,可以在一行的末尾添加 \ 搏熄,然后另起一行輸入命令:
shell:>register module --type source --name foo \
> --uri file:///tmp/bar
Successfully registered module 'source:foo'
快捷鍵使用
- ctrl + r 搜索輸入過歷史執(zhí)行過的命令。減少重復的輸入宵凌,提高操作效率止后。
- ctrl + a 跳轉(zhuǎn)到行頭輸入
- ctrl + e 跳轉(zhuǎn)到行尾輸入
- 上下箭頭 輸入完命令名字之后译株,按上下箭頭可以查閱之前輸入過的參數(shù)命令。
參數(shù)限制
可以使用注解乘寒,對參數(shù)進入限制匪补,防止用戶輸入錯誤烂翰,如下所示:
@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:>
上面這個檢測方法是命名是有規(guī)則的必須是命令名 + Availability皮官;另一種方式是使用注解指定檢測的方法名:
@ShellMethod("Download the nuclear codes.")
@ShellMethodAvailability("availabilityCheck")
public void download() {
[...]
}
public Availability availabilityCheck() {
return connected
? Availability.available()
: Availability.unavailable("you are not connected");
}