1。概述

简而言之,Spring Shell 我的项目 提供了一个交互式 shell,用于解决命令并应用 Spring 编程模型构建功能齐全的 CLI。

在本文中,咱们将摸索它的个性、要害类和正文,并实现几个自定义命令和自定义。

2。 Maven 依赖

首先,咱们须要将 spring-shell 依赖项增加到 pom.xml 中:

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

这个神器的最新版本能够在[这里](https://search.maven.org/clas... 22弹簧壳%22)。

3。拜访外壳

在咱们的应用程序中拜访 shell 有两种次要形式。

首先是在咱们应用程序的入口点疏导 shell 并让用户输出命令:

public static void main(String[] args) throws IOException {    Bootstrap.main(args);}

第二种是获取 JLineShellComponent 并以编程形式执行命令:

Bootstrap bootstrap = new Bootstrap();JLineShellComponent shell = bootstrap.getJLineShellComponent();shell.executeCommand("help");

咱们将应用第一种办法,因为它最适宜本文中的示例,然而,在源代码中您能够找到应用第二种模式的测试用例。

4。命令

shell 中曾经有几个内置命令,例如 clearhelpexit 等,它们提供了每个 CLI 的规范性能。

能够通过在实现 CommandMarker 接口的 Spring 组件中增加标有 @CliCommand 正文的办法来公开自定义命令。

该办法的每个参数都必须标有 @CliOption 正文,如果咱们不这样做,咱们将在尝试执行命令时遇到几个谬误。

4.1。向 Shell 增加命令

首先,咱们须要让 shell 晓得咱们的命令在哪里。为此,它须要文件 META-INF/spring/spring-shell-plugin.xml 存在于咱们的我的项目中,在那里,咱们能够应用 Spring 的组件扫描性能:

<beans ... >    <context:component-scan base-package="org.baeldung.shell.simple" /></beans>

一旦组件被 Spring 注册和实例化,它们就会被注册到 shell 解析器,并解决它们的正文。

让咱们创立两个简略的命令,一个用于获取 URL 的内容并显示它们,另一个用于将这些内容保留到文件中:

@Componentpublic class SimpleCLI implements CommandMarker {    @CliCommand(value = { "web-get", "wg" })    public String webGet(      @CliOption(key = "url") String url) {        return getContentsOfUrlAsString(url);    }        @CliCommand(value = { "web-save", "ws" })    public String webSave(      @CliOption(key = "url") String url,      @CliOption(key = { "out", "file" }) String file) {        String contents = getContentsOfUrlAsString(url);        try (PrintWriter out = new PrintWriter(file)) {            out.write(contents);        }        return "Done.";    }}

请留神,咱们能够别离将多个字符串传递给 @CliCommand@CliOptionvaluekey 属性,这容许咱们公开几个行为雷同的命令和参数。

当初,让咱们查看所有是否按预期工作:

spring-shell>web-get --url https://www.google.com<!doctype html ... spring-shell>web-save --url https://www.google.com --out contents.txtDone.

4.2。命令的可用性

咱们能够在返回 boolean 的办法上应用 @CliAvailabilityIndicator 正文,以在运行时更改命令是否应该裸露给 shell。

首先,让咱们创立一个办法来批改 web-save 命令的可用性:

private boolean adminEnableExecuted = false;@CliAvailabilityIndicator(value = "web-save")public boolean isAdminEnabled() {    return adminEnableExecuted;}

当初,让咱们创立一个命令来更改 adminEnableExecuted 变量:

@CliCommand(value = "admin-enable")public String adminEnable() {    adminEnableExecuted = true;    return "Admin commands enabled.";}

最初,让咱们验证一下:

spring-shell>web-save --url https://www.google.com --out contents.txtCommand 'web-save --url https://www.google.com --out contents.txt'  was found but is not currently available  (type 'help' then ENTER to learn about this command)spring-shell>admin-enableAdmin commands enabled.spring-shell>web-save --url https://www.google.com --out contents.txtDone.

4.3。必须的参数

默认状况下,所有命令参数都是可选的。然而,咱们能够应用 @CliOption 正文的 mandatory 属性使它们成为必须:

@CliOption(key = { "out", "file" }, mandatory = true)

当初,咱们能够测试一下,如果咱们不引入它,会导致谬误:

spring-shell>web-save --url https://www.google.comYou should specify option (--out) for this command

4.4。默认参数

@CliOption 的空 key 值使该参数成为默认值。在那里,咱们将收到不属于任何命名参数的 shell 中引入的值:

@CliOption(key = { "", "url" })

当初,让咱们查看它是否按预期工作:

spring-shell>web-get https://www.google.com<!doctype html ...

4.5。帮忙用户

@CliCommand@CliOption 正文提供了一个 help 属性,容许咱们在应用内置 help 命令或应用 tab 键取得主动实现时领导咱们的用户。

让咱们批改咱们的 web-get 以增加自定义帮忙音讯:

@CliCommand(  // ...  help = "Displays the contents of an URL")public String webGet(  @CliOption(    // ...    help = "URL whose contents will be displayed."  ) String url) {    // ...}

当初,用户能够确切地晓得咱们的命令做了什么:

spring-shell>help web-getKeyword:                    web-getKeyword:                    wgDescription:                Displays the contents of a URL.  Keyword:                  ** default **  Keyword:                  url    Help:                   URL whose contents will be displayed.    Mandatory:              false    Default if specified:   '__NULL__'    Default if unspecified: '__NULL__'* web-get - Displays the contents of a URL.* wg - Displays the contents of a URL.

5。定制

通过实现 BannerProviderPromptProviderHistoryFileNameProvider 接口,能够通过三种形式自定义 shell,它们都曾经提供了默认实现。

此外,咱们须要应用 @Order 正文来容许咱们的提供者优先于这些实现。

让咱们创立一个新横幅来开始咱们的定制:

@Component@Order(Ordered.HIGHEST_PRECEDENCE)public class SimpleBannerProvider extends DefaultBannerProvider {    public String getBanner() {        StringBuffer buf = new StringBuffer();        buf.append("=======================================")            .append(OsUtils.LINE_SEPARATOR);        buf.append("*          Baeldung Shell             *")            .append(OsUtils.LINE_SEPARATOR);        buf.append("=======================================")            .append(OsUtils.LINE_SEPARATOR);        buf.append("Version:")            .append(this.getVersion());        return buf.toString();    }    public String getVersion() {        return "1.0.1";    }    public String getWelcomeMessage() {        return "Welcome to Baeldung CLI";    }    public String getProviderName() {        return "Baeldung Banner";    }}

请留神,咱们还能够更改版本号和欢送信息。

当初,让咱们更改提醒:

@Component@Order(Ordered.HIGHEST_PRECEDENCE)public class SimplePromptProvider extends DefaultPromptProvider {    public String getPrompt() {        return "baeldung-shell";    }    public String getProviderName() {        return "Baeldung Prompt";    }}

最初,让咱们批改历史文件的名称:

@Component@Order(Ordered.HIGHEST_PRECEDENCE)public class SimpleHistoryFileNameProvider  extends DefaultHistoryFileNameProvider {    public String getHistoryFileName() {        return "baeldung-shell.log";    }    public String getProviderName() {        return "Baeldung History";    }}

历史文件将记录在 shell 中执行的所有命令,并将与咱们的应用程序放在一起。

所有就绪后,咱们能够调用咱们的 shell 并查看它的运行状况:

=======================================*          Baeldung Shell             *=======================================Version:1.0.1Welcome to Baeldung CLIbaeldung-shell>

6。转换器

到目前为止,咱们只应用简略类型作为命令的参数。 IntegerDateEnumFile 等常见类型曾经注册了默认转换器。

通过实现 Converter 接口,咱们还能够增加转换器来接管自定义对象。

让咱们创立一个能够将 String 转换为 URL 的转换器:

@Componentpublic class SimpleURLConverter implements Converter<URL> {    public URL convertFromText(      String value, Class<?> requiredType, String optionContext) {        return new URL(value);    }    public boolean getAllPossibleValues(      List<Completion> completions,      Class<?> requiredType,      String existingData,      String optionContext,      MethodTarget target) {        return false;    }    public boolean supports(Class<?> requiredType, String optionContext) {        return URL.class.isAssignableFrom(requiredType);    }}

最初,让咱们批改咱们的 web-getweb-save 命令:

public String webSave(... URL url) {    // ...}public String webSave(... URL url) {    // ...}

您可能曾经猜到了,这些命令的行为雷同。

7。小结

在本文中,咱们简要介绍了 Spring Shell 我的项目的外围个性。咱们可能奉献咱们的命令并应用咱们的提供程序自定义 shell,咱们依据不同的运行时条件更改了命令的可用性并创立了一个简略的类型转换器。

本文的残缺源代码能够在 GitHub 中找到。
本文亦通过 NoOne 的集体博客 发表。