亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Linux Shell > 正文

通過Spring Shell 開發 Java 命令行應用

2020-07-27 18:50:09
字體:
來源:轉載
供稿:網友

提到 Java,大家都會想到 Java 在服務器端應用開發中的使用。實際上,Java 在命令行應用的開發中也有一席之地。在很多情況下,相對于圖形用戶界面來說,命令行界面響應速度快,所占用的系統資源少。在與用戶進行交互的場景比較單一時,命令行界面是更好的選擇。命令行界面有其固定的交互模式。通常是由用戶輸入一系列的參數,在執行之后把相應的結果在控制臺輸出。命令行應用通常需要處理輸入參數的傳遞和驗證、輸出結果的格式化等任務。Spring Shell 可以幫助簡化這些常見的任務,讓開發人員專注于實現應用的業務邏輯。本文對 Spring Shell 進行詳細的介紹。

Spring Shell 入門

最簡單的創建 Spring Shell 應用的方式是使用 Spring Boot。從 Spring Initializr 網站(http://start.spring.io/)上創建一個新的基于 Apache Maven 的 Spring Boot 應用,然后添加 Spring Shell 相關的依賴即可。本文介紹的是 Spring Shell 2.0.0.M2 版本,目前還只是 Milestone 版本,因此需要在 pom.xml 中添加 Spring 提供的包含 Milestone 版本工件的 Maven 倉庫,如代碼清單 1 所示。否則的話,Maven 會無法找到相應的工件。

清單 1. 添加 Spring Shell 的 Maven 倉庫

<repositories> <repository> <id>spring-milestone</id> <name>Spring Repository</name> <url>https://repo.spring.io/milestone</url> </repository></repositories>

在添加了 Spring Shell 的 Maven 倉庫之后,可以在 Spring Boot 項目中添加對于spring-shell-starter 的依賴,如代碼清單 2 所示。

清單 2. 添加 Spring Shell 所需 Maven 依賴

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

我們接著可以創建第一個基于 Spring Shell 的命令行應用。該應用根據輸入的參數來輸出相應的問候語,完整的代碼如清單 3 所示。從代碼清單 3 中可以看到,在 Spring Shell 的幫助下,完整的實現代碼非常簡單。代碼的核心是兩個注解:@ShellComponent 聲明類GreetingApp 是一個 Spring Shell 的組件;@ShellMethod 表示方法 sayHi 是可以在命令行運行的命令。該方法的參數 name 是命令行的輸入參數,而其返回值是命令行執行的結果。

清單 3. 輸出問候語的命令行應用

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

接下來我們運行該應用。運行起來之后,該應用直接進入命令行提示界面,我們可以輸入 help 來輸出使用幫助。help 是 Spring Shell 提供的眾多內置命令之一,在列出的命令中,可以看到我們創建的 say-hi 命令。我們輸入"say-hi Alex"來運行該命令,可以看到輸出的結果"Hi Alex"。如果我們直接輸入"say-hi",會看到輸出的錯誤信息,告訴我們參數"--name"是必須的。從上面的例子可以看出,在 Spring Shell 的幫助下,創建一個命令行應用是非常簡單的。很多實用功能都已經默認提供了。在使用 Spring Initializr 創建的 Spring Boot 項目中,默認提供了一個單元測試用例。這個默認的單元測試用例與 Spring Shell 在使用時存在沖突。在進行代碼清單 3 中的項目的 Maven 構建時,該測試用例需要被禁用,否則構建過程會卡住。

參數傳遞與校驗

下面我們討論 Spring Shell 中的參數傳遞和校驗。Spring Shell 支持兩種不同類型的參數,分別是命名參數和位置參數。命名參數有名稱,可以通過類似--arg 的方式來指定;位置參數則按照其在方法的參數列表中的出現位置來進行匹配。命名參數和位置參數可以混合起來使用,不過命名參數的優先級更高,會首先匹配命名參數。每個參數都有默認的名稱,與方法中的對應的參數名稱一致。

在代碼清單 4 中的方法有 3 個參數 a、b 和 c。在調用該命令時,可以使用"echo1 --a 1 --b 2 --c 3",也可以使用"echo1 --a 1 2 3"或"echo1 1 3 --b 2"。其效果都是分別把 1,2 和 3 賦值給 a、b 和 c。

清單 4. 包含多個參數的命令方法

@ShellMethod("Echo1")public String echo1(int a, int b, int c) { return String.format("a = %d, b = %d, c = %d", a, b, c);}

如果不希望使用方法的參數名稱作為命令對應參數的名稱,可以通過@ShellOption 來標注所要使用的一個或多個參數名稱。我們可以通過指定多個參數名稱來提供不同的別名。在代碼清單 5 中,為參數 b 指定了一個名稱 boy??梢酝ㄟ^"echo2 1 --boy 2 3"來調用。

清單 5. 指定參數名稱

@ShellMethod("Echo2")public String echo2(int a, @ShellOption("--boy") int b, int c) { return String.format("a = %d, b = %d, c = %d", a, b, c);}

對于命名參數,默認使用的是"--"作為前綴,可以通過@ShellMethod 的屬性 prefix 來設置不同的前綴。方法對應的命令的名稱默認是從方法名稱自動得到的,可以通過屬性 key 來設置不同的名稱,屬性 value 表示的是命令的描述信息。如果參數是可選的,可以通過@ShellOption 的屬性 defaultValue 來設置默認值。在代碼清單 6 中,我們為方法 withDefault 指定了一個命令名稱 default,同時為參數 value 指定了默認值"Hello"。如果直接運行命令"default",輸出的結果是"Value: Hello";如果運行命令"default 123",則輸出的結果是"Value: 123"。

清單 6. 指定方法名稱和參數默認值

@ShellComponentpublic class NameAndDefaultValueApp { @ShellMethod(key = "default", value = "With default value") public void withDefault(@ShellOption(defaultValue = "Hello") final String value) { System.out.printf("Value: %s%n", value); }}

一個參數可以對應多個值。通過@ShellOption 屬性 arity 可以指定一個參數所對應的值的數量。這些參數會被添加到一個數組中,可以在方法中訪問。在代碼清單 7 中,方法 echo3 的參數 numbers 的 arity 值是 3,因此可以映射 3 個參數。在運行命令"echo3 1 2 3"時,輸出的結果是"a = 1, b =2, c = 3"。

清單 7. 參數對應多個值

@ShellMethod("Echo3")public String echo3(@ShellOption(arity = 3) int[] numbers) { return String.format("a = %d, b = %d, c = %d", numbers[0], numbers[1], numbers[2]);}

如果參數的類型是布爾類型 Boolean,在調用的時候不需要給出對應的值。當參數出現時就表示值為 true。

Spring Shell 支持對參數的值使用 Bean Validation API 進行驗證。比如我們可以用@Size 來限制字符串的長度,用@Min 和@Max 來限制數值的大小,如代碼清單 8 所示。

清單 8. 校驗參數

@ShellComponentpublic class ParametersValidationApp { @ShellMethod("String size") public String stringSize(@Size(min = 3, max = 16) String name) { return String.format("Your name is %s", name); } @ShellMethod("Number range") public String numberRange(@Min(10) @Max(100) int number) { return String.format("The number is %s", number); }}

結果處理

Spring Shell 在運行時,內部有一個處理循環。在每個循環的執行過程中,首先讀取用戶的輸入,然后進行相應的處理,最后再把處理的結果輸出。這其中的結果處理是由 org.springframework.shell.ResultHandler 接口來實現的。Spring Shell 中內置提供了對于不同類型結果的處理實現。命令執行的結果可能有很多種:如果用戶輸入的參數錯誤,輸出的結果應該是相應的提示信息;如果在命令的執行過程中出現了錯誤,則需要輸出相應的錯誤信息;用戶也可能直接退出命令行。Spring Shell 默認使用的處理實現是類 org.springframework.shell.result.IterableResultHandler。IterableResultHandler 負責處理 Iterable 類型的結果對象。對于 Iterable 中包含的每個對象,把實際的處理請求代理給另外一個 ResultHandler 來完成。IterableResultHandler 默認的代理實現是類 org.springframework.shell.result.TypeHierarchyResultHandler。TypeHierarchyResultHandler 其實是一個復合的處理器,它會把對于不同類型結果的 ResultHandler 接口的實現進行注冊,然后根據結果的類型來選擇相應的處理器實現。如果找不到類型完全匹配的處理器實現,則會沿著結果類型的層次結構樹往上查找,直到找到對應的處理器實現。Spring Shell 提供了對于 Object 類型結果的處理實現類 org.springframework.shell.result.DefaultResultHandler,因此所有的結果類型都可以得到處理。DefaultResultHandler 所做的處理只是把 Object 類型轉換成 String,然后輸出到控制臺。

了解了 Spring Shell 對于結果的處理方式之后,我們可以添加自己所需要的特定結果類型的處理實現。代碼清單 9 給了一個作為示例的處理結果類 PrefixedResult。PrefixedResult 中包含一個前綴 prefix 和實際的結果 result。

清單 9. 帶前綴的處理結果

public class PrefixedResult { private final String prefix; private final String result; public PrefixedResult(String prefix, String result) { this.prefix = prefix; this.result = result; } public String getPrefix() { return prefix; } public String getResult() { return result; }}

在代碼清單 10 中,我們為 PrefixedResult 添加了具體的處理器實現。該實現也非常簡單,只是把結果按照某個格式進行輸出。

清單 10. PrefixedResult 對應的處理器實現

@Componentpublic class PrefixedResultHandler implements ResultHandler<PrefixedResult> {  @Override public void handleResult(PrefixedResult result) { System.out.printf("%s --> %s%n", result.getPrefix(), result.getResult()); }}

在代碼清單 11 中,命令方法 resultHandler 返回的是一個 PrefixedResult 對象,因此會被代碼清單 10 中的處理器來進行處理,輸出相應的結果。

清單 11. 使用 PrefixedResult 的命令

@ShellComponentpublic class CustomResultHandlerApp { @ShellMethod("Result handler") public PrefixedResult resultHandler() { return new PrefixedResult("PRE", "Hello!"); }}

代碼清單 12 給出了具體的命令運行結果。

清單 12. 命令的處理結果

myshell=>result-handlerPRE --> Hello!

自定義提示符

在啟動命令行應用時,會發現該應用使用的是默認提示符"shell:>"。該提示符是可以定制的,只需要提供接口 org.springframework.shell.jline.PromptProvider 的實現即可。接口 PromptProvider 中只有一個方法,用來返回類型為 org.jline.utils.AttributedString 的提示符。在代碼清單 13 中,我們定義了一個 PromptProvider 接口的實現類,并使用"myshell=>"作為提示符,而且顏色為藍色。

清單 13. 自定義提示符

@Beanpublic PromptProvider promptProvider() { return () -> new AttributedString("myshell=>",  AttributedStyle.DEFAULT.foreground(AttributedStyle.BLUE));}

動態命令可用性

前面所創建的命令都是一直可用的。只要應用啟動起來,就可以使用這些命令。不過有些命令的可用性可能取決于應用的內部狀態,只有內部狀態滿足時,才可以使用這些命令。對于這些命令,Spring Shell 提供了類 org.springframework.shell.Availability 來表示命令的可用性。通過類 Availability 的靜態方法 available()和 unavailable()來分別創建表示命令可用和不可用的 Availability 對象。

在代碼清單 14 中,我們創建了兩個命令方法 runOnce()和 runAgain()。變量 run 作為內部狀態。在運行 runOnce()之后,變量 run 的值變為 true。命令 runAgain 的可用性由方法 runAgainAvailability()來確定。該方法根據變量 run 的值來決定 runAgain 是否可用。按照命名慣例,檢查命令可用性的方法的名稱是在命令方法名稱之后加上 Availability 后綴。如果需要使用不同的方法名稱,或是由一個檢查方法控制多個方法,可以在檢查方法上添加注解@ShellMethodAvailability 來聲明其控制的方法名稱。

清單 14. 動態命令可用性

@ShellComponentpublic class RunTwiceToEnableApp { private boolean run = false; @ShellMethod("Run once") public void runOnce() { this.run = true; } @ShellMethod("Run again") public void runAgain() { System.out.println("Run!"); } public Availability runAgainAvailability() { return run  ? Availability.available()  : Availability.unavailable("You should run runOnce first!"); }}

輸入參數轉換

之前的@ShellMethod 標注的方法使用的都是簡單類型的參數。Spring Shell 通過 Spring 框架的類型轉換系統來進行參數類型的轉換。Spring 框架已經內置提供了對常用類型的轉換邏輯,包括原始類型、String 類型、數組類型、集合類型、Java 8 的 Optional 類型、以及日期和時間類型等。我們可以通過 Spring 框架提供的擴展機制來添加自定義的轉換實現。

代碼清單 15 中的 User 類是作為示例的一個領域對象,包含了 id 和 name 兩個屬性。

清單 15. User

public class User { private final String id; private final String name; public User(String id, String name) { this.id = id; this.name = name; } public String getName() { return name; }}

代碼清單 16 中的 UserService 用來根據 id 來查找對應的 User 對象。作為示例,UserService 只是簡單使用一個 HashMap 來保存作為測試的 User 對象。

清單 16. UserService

public class UserService { private final Map<String, User> users = new HashMap<>(); public UserService() { users.put("alex", new User("alex", "Alex")); users.put("bob", new User("bob", "Bob")); } public User findUser(String id) { return users.get(id); }}

在代碼清單 17 中,UserConverter 實現了 Spring 中的 Converter 接口并添加了從 String 到 User 對象的轉換邏輯,即通過 UserService 來進行查找。

清單 17. 使用類型轉換

@Componentpublic class UserConverter implements Converter<String, User> { private final UserService userService = new UserService(); @Override public User convert(String source) { return userService.findUser(source); }}

在代碼清單 18 中,命令方法 user 的參數是 User 類型。當運行命令"user alex"時,輸入參數 alex 會通過代碼清單 17 中的類型轉換服務轉換成對應的 User 對象,然后輸出 User 對象的屬性值 name。如果找不到與輸入參數值對應的 User 對象,則輸出"User not found"。

清單 18. 使用類型轉換的命令

@ShellComponentpublic class UserCommandApp { @ShellMethod("User") public void user(final User user) { if (user != null) {  System.out.println(user.getName()); } else {  System.out.println("User not found"); } }}

命令組織方式

當創建很多個命令時,需要有一種把這些命令組織起來。Spring Shell 提供了不同的方式來對命令進行分組。處于同一分組的命令會在 help 命令輸出的幫助中出現在一起。默認情況下,同一個類中的命令會被添加到同一分組中。默認的分組名稱根據對應的 Java 類名來自動生成。除了默認分組之外,還可以顯式的設置分組??梢允褂聾ShellMethod 注解的屬性 group 來指定分組名稱;還可以為包含命令的類添加注解@ShellCommandGroup,則該類中的所有命令都在由@ShellCommandGroup 指定的分組中;還可以把@ShellCommandGroup 注解添加到包聲明中,則該包中的所有命令都在由@ShellCommandGroup 指定的分組中。

在代碼清單 19 中,通過@ShellCommandGroup 為命令所在類添加了自定義的分組名稱 Special。其中的方法 command2 則通過@ShellMethod 的 group 屬性指定了不同的分組名稱"Basic Group"。

清單 19. 組織命令

@ShellComponent@ShellCommandGroup("Special")public class CommandsGroupApp { @ShellMethod("Command1") public void command1() {} @ShellMethod(value = "Command2", group = "Basic Group") public void command2() {}}

圖 1 顯示了示例應用的 help 命令的輸出結果,從中可以看到命令的分組情況。

圖 1. 所有的命令列表

commands.png

內置命令

Spring Shell 提供了很多內置的命令,如下所示。

運行 help 命令可以列出來應用中的所有命令和對應的描述信息。
運行 clear 命令可以進行清屏操作。
運行 exit 命令可以退出命令行應用。
運行 script 命令可以執行一個文件中包含的所有命令。
如果不需要某個內置命令,可以通過把上下文環境中的屬性 spring.shell.command.<command>.enabled 的值設為 false 來禁用。如果希望禁用全部的內置命令,可以把 spring-shell-standard-commands 從 Maven 依賴中排除,如代碼清單 20 所示。

清單 20. 排除內置命令對應的 Maven 依賴

<dependency> <groupId>org.springframework.shell</groupId> <artifactId>spring-shell-starter</artifactId> <version>2.0.0.M2</version> <exclusions> <exclusion>  <groupId>org.springframework.shell</groupId>  <artifactId>spring-shell-standard-commands</artifactId> </exclusion> </exclusion></dependency>

小結

命令行應用以其簡單易用,占有資源少,速度快的特點,仍然在 Java 應用開發中占據一席之地。Spring Shell 為開發命令行應用提供了堅實的基礎,可以極大的提高開發效率。本文對 Spring Shell 進行了詳細的介紹,從基礎的入門,到參數的傳遞和校驗,再到結果處理、自定義提示符、動態命令可用性、輸入參數轉換、命令組織和內置命令等。在閱讀本文之后,讀者可以了解如何使用 Spring Shell 開發命令行應用。

以上所述是小編給大家介紹的通過Spring Shell 開發 Java 命令行應用,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩国产高清视频在线| 国产精品视频一区二区三区四| 精品免费在线观看| 欧美日韩国产页| 久久久久久com| 国产成人精品999| 国产在线精品成人一区二区三区| 亚洲欧美激情视频| 欧美日本精品在线| 亚洲免费视频网站| 高清日韩电视剧大全免费播放在线观看| 国产精品视频网站| 国产精品视频男人的天堂| 亚洲男人av电影| 久久成人综合视频| 欧美激情在线狂野欧美精品| 亚洲无av在线中文字幕| 亚洲字幕在线观看| 在线观看欧美www| 另类美女黄大片| 欧美亚洲成人免费| 最近2019中文字幕第三页视频| 欧美性生活大片免费观看网址| 国产精品日韩久久久久| 国产成人精品在线观看| 国产视频在线一区二区| 久久精品电影网站| 日韩久久精品成人| 一本大道久久加勒比香蕉| 亚洲精品v天堂中文字幕| 国模gogo一区二区大胆私拍| 国产性猛交xxxx免费看久久| 亚洲性xxxx| 国产精品亚洲一区二区三区| 2018中文字幕一区二区三区| 欧美激情aaaa| 成人午夜在线视频一区| 亚洲综合一区二区不卡| 亚洲第一精品久久忘忧草社区| 自拍亚洲一区欧美另类| 日韩av免费在线播放| 91青草视频久久| 国产成人一区三区| 国产一区二区三区在线观看视频| 国产婷婷成人久久av免费高清| 亚洲品质视频自拍网| 日韩有码在线视频| 欧美xxxx综合视频| 日韩欧美一区二区三区久久| 精品视频在线播放| 国外日韩电影在线观看| 精品国产欧美一区二区三区成人| 亚洲天天在线日亚洲洲精| 91国产在线精品| 亚洲成人1234| 一本色道久久88精品综合| 色综合男人天堂| 久久综合色影院| 日韩欧美亚洲国产一区| 欧美日韩国产中文精品字幕自在自线| 国产国语刺激对白av不卡| 九九视频直播综合网| 在线播放国产一区二区三区| 欧美一区二区三区图| 国产亚洲精品久久久久动| 久久久久久久久久久免费| 久久久久www| 欧美日本精品在线| 国产精品看片资源| 中文字幕综合一区| 在线国产精品视频| 亚洲香蕉av在线一区二区三区| 亚洲综合大片69999| 日韩欧美成人网| 98精品国产高清在线xxxx天堂| 国产精品久久久久不卡| 欧美精品在线免费| 久久久久久亚洲| 欧美国产亚洲精品久久久8v| 久久久91精品| 91国产一区在线| 日韩av在线电影网| 九九视频直播综合网| 欧美美最猛性xxxxxx| 亚洲国产欧美日韩精品| 一个人看的www欧美| 亚洲大胆人体在线| 欧美孕妇毛茸茸xxxx| 国产一区二区三区在线观看视频| 69视频在线播放| 成人在线观看视频网站| 亚洲欧美成人一区二区在线电影| 亚洲激情视频在线播放| 日韩欧美极品在线观看| 91精品视频专区| 欧美激情日韩图片| 清纯唯美日韩制服另类| 国产午夜精品久久久| 久久九九精品99国产精品| 亚洲mm色国产网站| 亚洲国产欧美日韩精品| 精品久久中文字幕| 亚洲精品欧美日韩| 精品欧美国产一区二区三区| 66m—66摸成人免费视频| 美女精品视频一区| 一本一本久久a久久精品牛牛影视| 欧美性猛交xxxx偷拍洗澡| 91久久久久久久一区二区| 亚洲热线99精品视频| 亚洲精品资源美女情侣酒店| 国产小视频国产精品| 国产在线观看一区二区三区| 日韩中文字幕在线视频播放| 亚洲福利小视频| 久久久久久久久久久亚洲| 亚洲第一级黄色片| 97久久超碰福利国产精品…| 爱福利视频一区| 亚洲一区二区久久| 欧美亚洲在线观看| 国产精品视频xxxx| 亚洲图片欧美日产| 不用播放器成人网| 日本久久久久久久久久久| 6080yy精品一区二区三区| 欧美乱大交做爰xxxⅹ性3| 欧美华人在线视频| 国产成人精品久久二区二区91| 97在线观看免费高清| 亚洲一区二区中文| 国产精品99一区| 日韩欧美在线视频| 日韩欧美在线看| 久久偷看各类女兵18女厕嘘嘘| 超碰97人人做人人爱少妇| 成人做爰www免费看视频网站| 69影院欧美专区视频| 国产精品一区二区av影院萌芽| 国产一区二区欧美日韩| 欧美日韩裸体免费视频| 91精品国产自产在线观看永久| 97在线日本国产| 九色精品免费永久在线| 欧美日韩精品二区| 亚洲精品国产精品国自产在线| 国产精品亚洲美女av网站| 日韩高清电影免费观看完整版| 九九热精品视频国产| 2018中文字幕一区二区三区| 亚洲免费精彩视频| 国产精品男人的天堂| 91大神福利视频在线| 午夜精品美女自拍福到在线| 亚洲福利视频二区| 欧美日韩激情美女| 国产精品扒开腿做爽爽爽视频| 国产成人免费av电影| 色综合色综合久久综合频道88| 日韩激情片免费| 日韩中文视频免费在线观看| 欧美一级大片在线免费观看| 国产婷婷色综合av蜜臀av| 成人午夜小视频|