8. 组件
组件是一组功能,这些功能要么是内置的,要么是其他的 您可以根据自己的需要重复使用或扩展。有问题的组件是 内置命令或提供更高级别的 UI 端组件 命令本身的功能。
8.1. 流程
当您使用流组件构建涉及
使用多个组件,您的实现可能会变得有点混乱。
为了简化这些用例,我们添加了一个可以将多个组件执行挂接在一起的
作为 “flow” 进行。ComponentFlow
以下清单显示了 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 相同。它
可以通过使用函数并返回目标组件 ID 来有条件地选择跳转到流中的位置。如果返回的 id 为 aither null 或不存在,则 flow 基本上会在那里停止。next
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.2. 流组件
从版本 2.1.x 开始,新的组件模型提供了 为常见用例创建更高级别用户交互的更简单方法, 例如以各种形式征求意见。这些通常只是纯文本 input 或从列表中选择内容。
内置组件的模板位于 Classpath 中。org/springframework/shell/component
内置组件通常遵循以下逻辑:
-
输入用户输入的运行循环。
-
生成与组件相关的上下文。
-
呈现组件状态的运行时状态。
-
退出。
-
渲染组件状态的最终状态。
Flow 为定义 更适合定义交互式命令流的组件。 |
8.2.1. 组件渲染
您可以通过以下两种方式之一实现组件渲染:完全
以编程方式或使用 ANTLR String模板。
严格来说,有一个简单的渲染器接口
,该 ID 将 .
这使您可以在 templating 和 code 之间进行选择。Function
Context
AttributedString
如果您不需要执行任何复杂或 您只想稍微修改现有的组件布局。渲染 然后,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.下表显示了这些上下文变量:
钥匙 | 描述 |
---|---|
|
组件呈现其结果后的值。 |
|
组件的名称 — 即其标题。 |
|
组件的可能消息集。 |
|
消息的级别 — 、 、 或 。 |
|
如果 level 为 ,则返回 。否则为 false。 |
|
如果 level 为 ,则返回 。否则为 false。 |
|
如果 level 为 ,则返回 。否则为 false。 |
|
原始用户输入。 |
钥匙 | 描述 |
---|---|
|
组件的名称 — 即其标题。 |
|
原始用户输入 — 主要用于筛选。 |
|
项状态的完整列表。 |
|
项状态的可见列表。 |
|
如果上下文处于 result 模式,则返回。 |
|
选择器中的当前光标行。 |
钥匙 | 描述 |
---|---|
|
终端的宽度,类型为 Integer,如果未设置,则默认为 NULL。 |
8.2.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
钥匙 | 描述 |
---|---|
|
默认值 (如果已设置)。否则为 null。 |
|
掩码输入值 |
|
掩码结果值 |
|
遮罩字符(如果已设置)。否则为 null。 |
|
|
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.2.3. 路径输入
path input 组件向用户请求 a 并提供有关路径本身的其他信息。Path
@ShellComponent
public class ComponentCommands extends AbstractShellComponent {
@ShellMethod(key = "component path input", 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 组件的典型输出:
上下文对象是 .下表描述了其上下文变量:PathInputContext
钥匙 | 描述 |
---|---|
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.2.4. 路径搜索
路径搜索组件询问 base directory for scan 和可选的搜索表达式。
结果显示在单个选择列表中,用户可以在其中选择路径。 可用于自定义组件行为。PathSearchConfig
PathSearchConfig config = new PathSearch.PathSearchConfig();
config.setMaxPathsShow(5);
config.setMaxPathsSearch(100);
config.setSearchForward(true);
config.setSearchCaseSensitive(false);
config.setSearchNormalize(false);
PathSearch component = new PathSearch(getTerminal(), "Enter value", config);
component.setResourceLoader(getResourceLoader());
component.setTemplateExecutor(getTemplateExecutor());
PathSearchContext context = component.run(PathSearchContext.empty());
return "Got value " + context.getResultValue();
搜索逻辑按原样传递到记录的算法中 在 Search Algorithms 中。 |
下图显示了路径搜索组件的典型输出:
上下文对象是 .下表描述了其上下文变量:PathSearchContext
钥匙 | 描述 |
---|---|
|
可用于呈现搜索结果的项目。 |
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.2.5. 确认
确认组件要求用户进行简单确认。它本质上是一个 是或否问题。
@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();
}
}
下图显示了确认组件的典型输出:
上下文对象是 .下表描述了其上下文变量:ConfirmationInputContext
钥匙 | 描述 |
---|---|
|
默认值 — 或 。 |
|
父上下文变量(请参阅 TextComponentContext 模板变量)。 |
8.2.6. 单选
单个 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 组件的典型输出:
上下文对象是 .下表描述了其上下文变量:SingleItemSelectorContext
钥匙 | 描述 |
---|---|
|
组件存在时的返回值。 |
|
可见项,其中 rows 包含名称和选定项的映射。 |
|
父上下文变量(请参阅 SelectorComponentContext 模板变量)。 |
您可以通过定义项目来预先选择项目以进行公开。这是
如果您知道 default 并允许用户仅按 进行选择,则很有用。
下面的清单设置了一个默认值: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.2.7. 多选
多选组件要求用户从列表中选择多个项目。 下面的清单显示了一个示例:
@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;
}
}
下图显示了一个典型的多选组件:
上下文对象是 .下表描述了其上下文变量:MultiItemSelectorContext
钥匙 | 描述 |
---|---|
|
组件存在时返回的值。 |
|
可见项,其中行包含 name、selected、on-row 和 enabled 项的映射。 |
|
父上下文变量(请参阅 SelectorComponentContext 模板变量)。 |