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 应用程序上下文。如果未覆盖,则 JLineHistoryBean 写入所有
命令复制到磁盘,以便它们在下次启动时再次可用。
8.1.4. 堆栈跟踪
当命令代码中发生异常时,shell 会捕获该异常,并显示一条简单的单行消息 以免用户收到太多信息。 但是,在某些情况下,了解到底发生了什么很重要(尤其是在异常具有嵌套原因时)。
为此, Spring Shell 会记住上次发生的异常,用户稍后可以使用stacktrace命令在控制台上打印所有详细信息。
8.1.5. 脚本
这scriptcommand 接受本地文件作为参数,并重放在那里找到的命令,一次一个。
从文件中读取的行为与在交互式 shell 中完全一样,因此会考虑以
作为注释并被忽略,而以 trigger line continuation 结尾的行。//\
8.1.6. 历史
这historycommand 显示已执行的命令的历史记录。
您可以使用一些配置选项来配置行为
的历史。历史记录保存在日志文件中,该文件默认处于启用状态,并且可以
通过设置spring.shell.history.enabled.日志文件的名称
从spring.application.name并默认为spring-shell.log,
您可以通过设置spring.shell.history.name.
默认情况下,将生成一个日志文件到当前工作目录,您可以指定该目录
通过设置spring.shell.config.location.此属性可以包含
占位符 ({userconfig}),该目录解析为通用共享配置目录。
| 运行 Spring Shell 应用程序,查看示例应用程序在使用这些选项时的工作原理。 |
8.1.7. 完成
这completionCommand 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/componentclasspath 的
内置组件通常遵循以下逻辑:
-
输入用户输入的运行循环。
-
生成与组件相关的上下文。
-
呈现组件状态的运行时状态。
-
退出。
-
渲染组件状态的最终状态。
| Flow 为定义 更适合定义交互式命令流的组件。 |
8.3.1. 组件渲染
您可以通过以下两种方式之一实现组件渲染:完全
以编程方式或使用 ANTLR String模板。
严格来说,有一个简单的Functionrenderer 接口
这需要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 模板变量)。 |