8. 组件

组件是一组功能,这些功能要么是内置的,要么是其他的 您可以根据自己的需要重复使用或扩展。有问题的组件是 内置命令或提供更高级别的 UI 端组件 命令本身的功能。spring-doc.cn

8.1. 流程

当您使用流组件构建涉及 使用多个组件,您的实现可能会变得有点混乱。 为了简化这些用例,我们添加了一个可以将多个组件执行挂接在一起的 作为 “flow” 进行。ComponentFlowspring-doc.cn

以下清单显示了 shell 中的流及其输出的示例:spring-doc.cn

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 基本上会在那里停止。nextspring-doc.cn

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 或从列表中选择内容。spring-doc.cn

内置组件的模板位于 Classpath 中。org/springframework/shell/componentspring-doc.cn

内置组件通常遵循以下逻辑:spring-doc.cn

  1. 输入用户输入的运行循环。spring-doc.cn

  2. 生成与组件相关的上下文。spring-doc.cn

  3. 呈现组件状态的运行时状态。spring-doc.cn

  4. 退出。spring-doc.cn

  5. 渲染组件状态的最终状态。spring-doc.cn

Flow 为定义 更适合定义交互式命令流的组件。

8.2.1. 组件渲染

您可以通过以下两种方式之一实现组件渲染:完全 以编程方式或使用 ANTLR String模板。 严格来说,有一个简单的渲染器接口 ,该 ID 将 . 这使您可以在 templating 和 code 之间进行选择。FunctionContextAttributedStringspring-doc.cn

如果您不需要执行任何复杂或 您只想稍微修改现有的组件布局。渲染 然后,THROUGH CODE 让您可以灵活地执行任何需要的操作。spring-doc.cn

渲染的编程方式是创建一个 :Functionspring-doc.cn

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());
	}
}

然后你可以将其挂接到一个组件上:spring-doc.cn

@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.下表显示了这些上下文变量:spring-doc.cn

表 7.TextComponentContext 模板变量
钥匙 描述

resultValuespring-doc.cn

组件呈现其结果后的值。spring-doc.cn

namespring-doc.cn

组件的名称 — 即其标题。spring-doc.cn

messagespring-doc.cn

组件的可能消息集。spring-doc.cn

messageLevelspring-doc.cn

消息的级别 — 、 、 或 。INFOWARNERRORspring-doc.cn

hasMessageLevelInfospring-doc.cn

如果 level 为 ,则返回 。否则为 false。trueINFOspring-doc.cn

hasMessageLevelWarnspring-doc.cn

如果 level 为 ,则返回 。否则为 false。trueWARNspring-doc.cn

hasMessageLevelErrorspring-doc.cn

如果 level 为 ,则返回 。否则为 false。trueERRORspring-doc.cn

inputspring-doc.cn

原始用户输入。spring-doc.cn

表 8.SelectorComponentContext 模板变量
钥匙 描述

namespring-doc.cn

组件的名称 — 即其标题。spring-doc.cn

inputspring-doc.cn

原始用户输入 — 主要用于筛选。spring-doc.cn

itemStatesspring-doc.cn

项状态的完整列表。spring-doc.cn

itemStateViewspring-doc.cn

项状态的可见列表。spring-doc.cn

isResultspring-doc.cn

如果上下文处于 result 模式,则返回。truespring-doc.cn

cursorRowspring-doc.cn

选择器中的当前光标行。spring-doc.cn

表 9.ComponentContext 模板变量
钥匙 描述

terminalWidthspring-doc.cn

终端的宽度,类型为 Integer,如果未设置,则默认为 NULLspring-doc.cn

8.2.2. 字符串输入

字符串输入组件要求用户提供简单的文本输入,并可选择屏蔽值 如果内容包含敏感内容。下面的清单显示了一个示例:spring-doc.cn

@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();
	}
}

下图显示了字符串输入组件的典型输出:spring-doc.cn

文本输入

上下文对象是 .下表列出了其 context 变量:StringInputContextspring-doc.cn

表 10.StringInputContext 模板变量
钥匙 描述

defaultValuespring-doc.cn

默认值 (如果已设置)。否则为 null。spring-doc.cn

maskedInputspring-doc.cn

掩码输入值spring-doc.cn

maskedResultValuespring-doc.cn

掩码结果值spring-doc.cn

maskCharacterspring-doc.cn

遮罩字符(如果已设置)。否则为 null。spring-doc.cn

hasMaskCharacterspring-doc.cn

true如果设置了掩码字符。否则为 false。spring-doc.cn

modelspring-doc.cn

父上下文变量(请参阅 TextComponentContext 模板变量)。spring-doc.cn

8.2.3. 路径输入

path input 组件向用户请求 a 并提供有关路径本身的其他信息。Pathspring-doc.cn

@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 组件的典型输出:spring-doc.cn

文本输入

上下文对象是 .下表描述了其上下文变量:PathInputContextspring-doc.cn

表 11.PathInputContext 模板变量
钥匙 描述

modelspring-doc.cn

父上下文变量(请参阅 TextComponentContext 模板变量)。spring-doc.cn

8.2.4. 路径搜索

路径搜索组件询问 base directory for scan 和可选的搜索表达式。 结果显示在单个选择列表中,用户可以在其中选择路径。 可用于自定义组件行为。PathSearchConfigspring-doc.cn

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 中。

下图显示了路径搜索组件的典型输出:spring-doc.cn

文本输入

上下文对象是 .下表描述了其上下文变量:PathSearchContextspring-doc.cn

表 12.PathSearchContext 模板变量
钥匙 描述

pathViewItemsspring-doc.cn

可用于呈现搜索结果的项目。spring-doc.cn

modelspring-doc.cn

父上下文变量(请参阅 TextComponentContext 模板变量)。spring-doc.cn

8.2.5. 确认

确认组件要求用户进行简单确认。它本质上是一个 是或否问题。spring-doc.cn

@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();
	}
}

下图显示了确认组件的典型输出:spring-doc.cn

文本输入

上下文对象是 .下表描述了其上下文变量:ConfirmationInputContextspring-doc.cn

表 13.ConfirmationInputContext 模板变量
钥匙 描述

defaultValuespring-doc.cn

默认值 — 或 。truefalsespring-doc.cn

modelspring-doc.cn

父上下文变量(请参阅 TextComponentContext 模板变量)。spring-doc.cn

8.2.6. 单选

单个 select 组件要求用户从列表中选择一个项目。它类似于简单的 Dropbox 实现。下面的清单显示了一个示例:spring-doc.cn

@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 组件的典型输出:spring-doc.cn

文本输入

上下文对象是 .下表描述了其上下文变量:SingleItemSelectorContextspring-doc.cn

表 14.SingleItemSelectorContext 模板变量
钥匙 描述

valuespring-doc.cn

组件存在时的返回值。spring-doc.cn

rowsspring-doc.cn

可见项,其中 rows 包含名称和选定项的映射。spring-doc.cn

modelspring-doc.cn

父上下文变量(请参阅 SelectorComponentContext 模板变量)。spring-doc.cn

您可以通过定义项目来预先选择项目以进行公开。这是 如果您知道 default 并允许用户仅按 进行选择,则很有用。 下面的清单设置了一个默认值:Enterspring-doc.cn

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. 多选

多选组件要求用户从列表中选择多个项目。 下面的清单显示了一个示例:spring-doc.cn

@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;
	}
}

下图显示了一个典型的多选组件:spring-doc.cn

文本输入

上下文对象是 .下表描述了其上下文变量:MultiItemSelectorContextspring-doc.cn

表 15.MultiItemSelectorContext 模板变量
钥匙 描述

valuesspring-doc.cn

组件存在时返回的值。spring-doc.cn

rowsspring-doc.cn

可见项,其中行包含 name、selected、on-row 和 enabled 项的映射。spring-doc.cn

modelspring-doc.cn

父上下文变量(请参阅 SelectorComponentContext 模板变量)。spring-doc.cn