8. 组件
组件是一组功能,这些功能要么是内置的,要么是其他的 您可以根据自己的需要重复使用或扩展。有问题的组件是 内置命令或提供更高级别的 UI 端组件 命令本身的功能。
8.1. 内置命令
8.1.1. 帮助
运行 shell 应用程序通常意味着用户处于图形受限的
环境。此外,虽然在手机时代我们几乎总是保持连接,
访问 Web 浏览器或任何其他富 UI 应用程序(如 PDF 查看器)可能并不总是
是可能的。这就是为什么 shell 命令必须正确地自记录很重要的原因,这就是help
命令进来。
打字help
+ ENTER
列出 shell 已知的所有命令(包括不可用的命令)
以及他们工作的简短描述,类似于以下内容:
my-shell:>help
AVAILABLE COMMANDS
Built-In Commands
exit: Exit the shell.
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit: Exit the shell.
history: Display or save the history of previously run commands
completion bash: Generate bash completion script
version: Show version info
script: Read and execute commands from a file.
打字help <command>
显示有关命令的更多详细信息,包括可用参数、其
类型、是否为必填项以及其他详细信息。
下面的清单显示了help
命令应用于自身:
my-shell:>help help
NAME
help - Display help about available commands
SYNOPSIS
help --command String
OPTIONS
--command or -C String
The command to obtain help for.
[Optional]
帮助是模板化的,如果需要,可以进行自定义。设置位于spring.shell.command.help
您可以使用的位置enabled
要禁用命令,grouping-mode
取group
或flat
如果要通过拼合来隐藏组
a 结构,command-template
要定义命令帮助输出的模板,commands-template
定义
命令列表的输出。
如果spring.shell.command.help.grouping-mode=flat
设置,则 help 将显示:
my-shell:>help help
AVAILABLE COMMANDS
exit: Exit the shell.
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit: Exit the shell.
history: Display or save the history of previously run commands
completion bash: Generate bash completion script
version: Show version info
script: Read and execute commands from a file.
输出help
和help <commmand>
都使用默认实现进行模板化
可以更改。
选择spring.shell.command.help.commands-template
默认为classpath:template/help-commands-default.stg
并传递GroupsInfoModel
作为模型。
选择spring.shell.command.help.command-template
默认为classpath:template/help-command-default.stg
并传递CommandInfoModel
作为模型。
钥匙 | 描述 |
---|---|
|
|
|
commands 变量(请参阅 GroupCommandInfoModel 变量)。 |
|
commands 变量(请参阅 CommandInfoModel 变量)。 |
|
|
钥匙 | 描述 |
---|---|
|
组的名称(如果已设置)。否则为空。 |
|
命令 (如果已设置)。否则为空。Type 是多值,请参阅 CommandInfoModel 变量。 |
钥匙 | 描述 |
---|---|
|
命令的名称(如果已设置)。否则为 null。类型为 string 并包含 full 命令。 |
|
命令的名称(如果已设置)。否则为 null。类型本质上是多值 |
|
可能的别名(如果已设置)。类型是带字符串的多值。 |
|
命令的描述(如果已设置)。否则为 null。 |
|
parameters 变量(如果已设置)。否则为空。Type 是多值,请参阅 CommandParameterInfoModel 变量。 |
|
可用性变量(请参阅 CommandAvailabilityInfoModel 变量)。 |
钥匙 | 描述 |
---|---|
|
参数的类型(如果已设置)。否则为 null。 |
|
参数(如果已设置)。否则为 null。类型是带字符串的多值。 |
|
|
|
参数的描述 (如果已设置)。否则为 null。 |
|
参数的默认值 (如果已设置)。否则为 null。 |
|
|
钥匙 | 描述 |
---|---|
|
|
|
如果设置了 not available (如果已设置),则为原因。否则为 null。 |
8.1.3. 退出
这quit
命令(也别名为exit
) 请求 shell 正常退出
关闭 Spring 应用程序上下文。如果未覆盖,则 JLineHistory
Bean 写入所有
命令复制到磁盘,以便它们在下次启动时再次可用。
8.1.4. 堆栈跟踪
当命令代码中发生异常时,shell 会捕获该异常,并显示一条简单的单行消息 以免用户收到太多信息。 但是,在某些情况下,了解到底发生了什么很重要(尤其是在异常具有嵌套原因时)。
为此, Spring Shell 会记住上次发生的异常,用户稍后可以使用stacktrace
命令在控制台上打印所有详细信息。
8.1.5. 脚本
这script
command 接受本地文件作为参数,并重放在那里找到的命令,一次一个。
从文件中读取的行为与在交互式 shell 中完全一样,因此会考虑以
作为注释并被忽略,而以 trigger line continuation 结尾的行。//
\
8.1.6. 历史
这history
command 显示已执行的命令的历史记录。
您可以使用一些配置选项来配置行为
的历史。历史记录保存在日志文件中,该文件默认处于启用状态,并且可以
通过设置spring.shell.history.enabled
.日志文件的名称
从spring.application.name
并默认为spring-shell.log
,
您可以通过设置spring.shell.history.name
.
默认情况下,将生成一个日志文件到当前工作目录,您可以指定该目录
通过设置spring.shell.config.location
.此属性可以包含
占位符 ({userconfig}
),该目录解析为通用共享配置目录。
运行 Spring Shell 应用程序,查看示例应用程序在使用这些选项时的工作原理。 |
8.1.7. 完成
这completion
Command Set 允许您创建可以使用的脚本文件
使用 AM OS shell 实现来提供补全。这在以下情况下非常有用
使用非交互模式。
目前,唯一的实现是 bash,它适用于bash
子命令。
8.1.8. 版本
这version
命令通过集成到
靴子的BuildProperties
和GitProperties
如果 shell 应用程序中存在这些 cookie。
默认情况下,只显示版本信息,您可以通过配置启用其他信息
选项。
相关设置位于spring.shell.command.version
,您可以在其中使用enabled
自
禁用命令,并可选择使用template
.您可以使用show-build-artifact
,show-build-group
,show-build-name
,show-build-time
,show-build-version
,show-git-branch
,show-git-commit-id
,show-git-short-commit-id
和show-git-commit-time
控制命令
字段。
模板默认为classpath:template/version-default.st
,您可以定义
您自己的,如下例所示:
<buildVersion>
此设置将输出如下内容:
X.X.X
您可以将以下属性添加到默认模板渲染中:buildVersion
,buildGroup
,buildGroup
,buildName
,buildTime
,gitShortCommitId
,gitCommitId
,gitBranch
和gitCommitTime
.
8.2. 流程
当您使用流组件构建涉及
使用多个组件,您的实现可能会变得有点混乱。
为了简化这些用例,我们添加了一个ComponentFlow
可以将多个组件执行挂接在一起
作为 “flow” 进行。
以下清单显示了 shell 中的流及其输出的示例:
static class FlowSampleComplex {
@Autowired
private ComponentFlow.Builder componentFlowBuilder;
public void runFlow() {
Map<String, String> single1SelectItems = new HashMap<>();
single1SelectItems.put("key1", "value1");
single1SelectItems.put("key2", "value2");
List<SelectItem> multi1SelectItems = Arrays.asList(SelectItem.of("key1", "value1"),
SelectItem.of("key2", "value2"), SelectItem.of("key3", "value3"));
ComponentFlow flow = componentFlowBuilder.clone().reset()
.withStringInput("field1")
.name("Field1")
.defaultValue("defaultField1Value")
.and()
.withStringInput("field2")
.name("Field2")
.and()
.withConfirmationInput("confirmation1")
.name("Confirmation1")
.and()
.withPathInput("path1")
.name("Path1")
.and()
.withSingleItemSelector("single1")
.name("Single1")
.selectItems(single1SelectItems)
.and()
.withMultiItemSelector("multi1")
.name("Multi1")
.selectItems(multi1SelectItems)
.and()
.build();
flow.run();
}
}
组件的正常执行顺序与使用 builder 定义的 Sequence 相同。它
可以通过使用next
函数并返回目标组件 ID。如果返回的 id 为 aither null 或不存在,则 flow 基本上会在那里停止。
static class FlowSampleConditional {
@Autowired
private ComponentFlow.Builder componentFlowBuilder;
public void runFlow() {
Map<String, String> single1SelectItems = new HashMap<>();
single1SelectItems.put("Field1", "field1");
single1SelectItems.put("Field2", "field2");
ComponentFlow flow = componentFlowBuilder.clone().reset()
.withSingleItemSelector("single1")
.name("Single1")
.selectItems(single1SelectItems)
.next(ctx -> ctx.getResultItem().get().getItem())
.and()
.withStringInput("field1")
.name("Field1")
.defaultValue("defaultField1Value")
.next(ctx -> null)
.and()
.withStringInput("field2")
.name("Field2")
.defaultValue("defaultField2Value")
.next(ctx -> null)
.and()
.build();
flow.run();
}
}
运行流程的结果返回ComponentFlowResult ,您可以
用于执行进一步的作。 |
8.3. 流组件
从版本 2.1.x 开始,新的组件模型提供了 为常见用例创建更高级别用户交互的更简单方法, 例如以各种形式征求意见。这些通常只是纯文本 input 或从列表中选择内容。
内置组件的模板位于org/springframework/shell/component
classpath 的
内置组件通常遵循以下逻辑:
-
输入用户输入的运行循环。
-
生成与组件相关的上下文。
-
呈现组件状态的运行时状态。
-
退出。
-
渲染组件状态的最终状态。
Flow 为定义 更适合定义交互式命令流的组件。 |
8.3.1. 组件渲染
您可以通过以下两种方式之一实现组件渲染:完全
以编程方式或使用 ANTLR String模板。
严格来说,有一个简单的Function
renderer 接口
这需要Context
作为输入,并输出AttributedString
.
这使您可以在 templating 和 code 之间进行选择。
如果您不需要执行任何复杂或 您只想稍微修改现有的组件布局。渲染 然后,THROUGH CODE 让您可以灵活地执行任何需要的作。
渲染的编程方式是创建一个Function
:
class StringInputCustomRenderer implements Function<StringInputContext, List<AttributedString>> {
@Override
public List<AttributedString> apply(StringInputContext context) {
AttributedStringBuilder builder = new AttributedStringBuilder();
builder.append(context.getName());
builder.append(" ");
if (context.getResultValue() != null) {
builder.append(context.getResultValue());
}
else {
String input = context.getInput();
if (StringUtils.hasText(input)) {
builder.append(input);
}
else {
builder.append("[Default " + context.getDefaultValue() + "]");
}
}
return Arrays.asList(builder.toAttributedString());
}
}
然后你可以将其挂接到一个组件上:
@ShellMethod(key = "component stringcustom", value = "String input", group = "Components")
public String stringInputCustom(boolean mask) {
StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue",
new StringInputCustomRenderer());
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
if (mask) {
component.setMaskCharacter('*');
}
StringInputContext context = component.run(StringInputContext.empty());
return "Got value " + context.getResultValue();
}
组件有自己的上下文,但通常共享一些功能 从父组件 types.下表显示了这些上下文变量:
钥匙 | 描述 |
---|---|
|
组件呈现其结果后的值。 |
|
组件的名称 — 即其标题。 |
|
组件的可能消息集。 |
|
消息的级别 — 以下之一 |
|
返回 |
|
返回 |
|
返回 |
|
原始用户输入。 |
钥匙 | 描述 |
---|---|
|
组件的名称 — 即其标题。 |
|
原始用户输入 — 主要用于筛选。 |
|
项状态的完整列表。 |
|
项状态的可见列表。 |
|
返回 |
|
选择器中的当前光标行。 |
8.3.2. 字符串输入
字符串输入组件要求用户提供简单的文本输入,并可选择屏蔽值 如果内容包含敏感内容。下面的清单显示了一个示例:
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component string", value = "String input", group = "Components")
public String stringInput(boolean mask) {
StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue");
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
if (mask) {
component.setMaskCharacter('*');
}
StringInputContext context = component.run(StringInputContext.empty());
return "Got value " + context.getResultValue();
}
}
下图显示了字符串输入组件的典型输出:
context 对象是StringInputContext
.下表列出了其 context 变量:
钥匙 | 描述 |
---|---|
|
默认值 (如果已设置)。否则为 null。 |
|
掩码输入值 |
|
掩码结果值 |
|
遮罩字符(如果已设置)。否则为 null。 |
|
|
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.3.3. 路径输入
路径输入组件要求用户输入Path
并提供有关路径本身的其他信息。
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component path", value = "Path input", group = "Components")
public String pathInput() {
PathInput component = new PathInput(getTerminal(), "Enter value");
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
PathInputContext context = component.run(PathInputContext.empty());
return "Got value " + context.getResultValue();
}
}
下图显示了 path input 组件的典型输出:
context 对象是PathInputContext
.下表描述了其上下文变量:
钥匙 | 描述 |
---|---|
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.3.4. 确认
确认组件要求用户进行简单确认。它本质上是一个 是或否问题。
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component confirmation", value = "Confirmation input", group = "Components")
public String confirmationInput(boolean no) {
ConfirmationInput component = new ConfirmationInput(getTerminal(), "Enter value", !no);
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
ConfirmationInputContext context = component.run(ConfirmationInputContext.empty());
return "Got value " + context.getResultValue();
}
}
下图显示了确认组件的典型输出:
context 对象是ConfirmationInputContext
.下表描述了其上下文变量:
钥匙 | 描述 |
---|---|
|
默认值 — 要么 |
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.3.5. 单选
单个 select 组件要求用户从列表中选择一个项目。它类似于简单的 Dropbox 实现。下面的清单显示了一个示例:
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component single", value = "Single selector", group = "Components")
public String singleSelector() {
SelectorItem<String> i1 = SelectorItem.of("key1", "value1");
SelectorItem<String> i2 = SelectorItem.of("key2", "value2");
List<SelectorItem<String>> items = Arrays.asList(i1, i2);
SingleItemSelector<String, SelectorItem<String>> component = new SingleItemSelector<>(getTerminal(),
items, "testSimple", null);
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
SingleItemSelectorContext<String, SelectorItem<String>> context = component
.run(SingleItemSelectorContext.empty());
String result = context.getResultItem().flatMap(si -> Optional.ofNullable(si.getItem())).get();
return "Got value " + result;
}
}
下图显示了单个 select 组件的典型输出:
context 对象是SingleItemSelectorContext
.下表描述了其上下文变量:
钥匙 | 描述 |
---|---|
|
组件存在时的返回值。 |
|
可见项,其中 rows 包含名称和选定项的映射。 |
|
父上下文变量(请参阅 SelectorComponentContext 模板变量)。 |
您可以通过定义项目来预先选择项目以进行公开。这是
如果您知道默认值并允许用户仅按Enter
进行选择。
下面的清单设置了一个默认值:
SelectorItem<String> i1 = SelectorItem.of("key1", "value1");
SelectorItem<String> i2 = SelectorItem.of("key2", "value2");
List<SelectorItem<String>> items = Arrays.asList(i1, i2);
SingleItemSelector<String, SelectorItem<String>> component = new SingleItemSelector<>(getTerminal(),
items, "testSimple", null);
component.setDefaultExpose(i2);
8.3.6. 多选
多选组件要求用户从列表中选择多个项目。 下面的清单显示了一个示例:
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component multi", value = "Multi selector", group = "Components")
public String multiSelector() {
List<SelectorItem<String>> items = new ArrayList<>();
items.add(SelectorItem.of("key1", "value1"));
items.add(SelectorItem.of("key2", "value2", false, true));
items.add(SelectorItem.of("key3", "value3"));
MultiItemSelector<String, SelectorItem<String>> component = new MultiItemSelector<>(getTerminal(),
items, "testSimple", null);
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
MultiItemSelectorContext<String, SelectorItem<String>> context = component
.run(MultiItemSelectorContext.empty());
String result = context.getResultItems().stream()
.map(si -> si.getItem())
.collect(Collectors.joining(","));
return "Got value " + result;
}
}
下图显示了一个典型的多选组件:
context 对象是MultiItemSelectorContext
.下表描述了其上下文变量:
钥匙 | 描述 |
---|---|
|
组件存在时返回的值。 |
|
可见项,其中行包含 name、selected、on-row 和 enabled 项的映射。 |
|
父上下文变量(请参阅 SelectorComponentContext 模板变量)。 |