插件版本更新

This commit is contained in:
张家训
2026-06-09 09:41:30 +08:00
parent 75a1049d8e
commit b964fef4dd
13 changed files with 661 additions and 276 deletions
@@ -1,7 +1,7 @@
package com.example.workutils;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.tool.ToolRegistry;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -16,10 +16,10 @@ import java.util.Scanner;
@Slf4j
public class WorkUtilsApplication implements CommandLineRunner {
private final ToolRegistry toolRegistry;
private final PluginManager pluginManager;
public WorkUtilsApplication(ToolRegistry toolRegistry) {
this.toolRegistry = toolRegistry;
public WorkUtilsApplication(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
public static void main(String[] args) {
@@ -37,25 +37,25 @@ public class WorkUtilsApplication implements CommandLineRunner {
private void showInteractiveMenu() {
Scanner scanner = new Scanner(System.in);
toolRegistry.runMainMenu(scanner);
pluginManager.runMainMenu(scanner);
}
/**
* 命令行模式:通过ToolRegistry按命令名分发到对应Tool
* 启动类不依赖任何具体业务Service
* 命令行模式:通过 PluginManager 按命令名分发到对应 Plugin
* 启动类不依赖任何具体业务 Service
*/
private void processCommand(String... args) throws Exception {
String command = args[0].toLowerCase();
Optional<Tool> toolOpt = toolRegistry.getToolByCommand(command);
if (toolOpt.isPresent()) {
Tool tool = toolOpt.get();
Optional<Plugin> pluginOpt = pluginManager.getPluginByCommand(command);
if (pluginOpt.isPresent()) {
Plugin plugin = pluginOpt.get();
try {
// args[0]是命令名,从args[1]开始传给tool
String[] toolArgs = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0];
tool.executeCommand(toolArgs);
// args[0]是命令名,从args[1]开始传给plugin
String[] pluginArgs = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0];
plugin.executeCommand(pluginArgs);
} catch (Exception e) {
log.error("命令执行失败: {} [{}]", tool.getName(), tool.getId(), e);
log.error("命令执行失败: {} [{}]", plugin.getName(), plugin.getId(), e);
System.err.println("命令执行失败: " + e.getMessage());
}
} else {
@@ -2,7 +2,8 @@ package com.example.workutils.biz.batch;
import com.example.workutils.biz.mybatisexport.service.MyBatisExportService;
import com.example.workutils.biz.scanner.service.ScannerService;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -12,19 +13,26 @@ import java.util.List;
import java.util.Scanner;
/**
* 批量处理工具
* 批量处理插件(实现 Plugin 接口)
* 仅负责菜单展示和用户交互,业务逻辑委托给各Service
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class BatchTool implements Tool {
public class BatchTool implements Plugin {
@FunctionalInterface
public interface ExceptionRunnable {
void run() throws Exception;
}
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
.id("batch")
.name("批量处理")
.version("1.0.0")
.description("一键执行多种检查任务")
.build();
private static final String[] MENU_OPTIONS = {
"1. 执行所有检查",
"2. 自定义组合检查",
@@ -42,13 +50,8 @@ public class BatchTool implements Tool {
private final MyBatisExportService myBatisExportService;
@Override
public String getId() {
return "batch";
}
@Override
public String getName() {
return "批量处理";
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
@@ -2,7 +2,8 @@ package com.example.workutils.biz.git;
import com.example.workutils.biz.git.service.GitService;
import com.example.workutils.biz.git.service.internal.GitCommandExecutor;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -13,12 +14,19 @@ import java.util.Scanner;
import java.util.stream.Collectors;
/**
* Git仓库健康检测工具入口(符合 Tool 规范)
* Git仓库健康检测插件(实现 Plugin 接口)
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class GitTool implements Tool {
public class GitTool implements Plugin {
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
.id("git-health")
.name("Git仓库健康检测")
.version("1.0.0")
.description("检测和修复Git仓库健康状态")
.build();
private static final String[] MENU_OPTIONS = {
"1. 检测所有仓库健康状态",
@@ -29,13 +37,8 @@ public class GitTool implements Tool {
private final GitService gitService;
@Override
public String getId() {
return "git-health";
}
@Override
public String getName() {
return "Git仓库健康检测";
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
@@ -1,7 +1,8 @@
package com.example.workutils.biz.mybatisexport;
import com.example.workutils.biz.mybatisexport.service.MyBatisExportService;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -10,12 +11,19 @@ import java.util.Arrays;
import java.util.Scanner;
/**
* MyBatis SQL导出工具入口(符合 Tool 规范)
* MyBatis SQL导出插件(实现 Plugin 接口)
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class MyBatisExportTool implements Tool {
public class MyBatisExportTool implements Plugin {
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
.id("mybatisexport")
.name("MyBatis SQL导出")
.version("1.0.0")
.description("从MyBatis XML中提取SQL并导出为CSV")
.build();
private static final String[] MENU_OPTIONS = {
"1. 导出所有SQL",
@@ -29,13 +37,8 @@ public class MyBatisExportTool implements Tool {
private final MyBatisExportService myBatisExportService;
@Override
public String getId() {
return "mybatisexport";
}
@Override
public String getName() {
return "MyBatis SQL导出";
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
@@ -1,7 +1,8 @@
package com.example.workutils.biz.mybatisgenerator;
import com.example.workutils.biz.mybatisgenerator.service.generator.MyBatisGeneratorService;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -11,12 +12,19 @@ import java.util.List;
import java.util.Scanner;
/**
* MyBatis逆向工程工具入口(符合 Tool 规范)
* MyBatis逆向工程插件(实现 Plugin 接口)
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class MyBatisGeneratorTool implements Tool {
public class MyBatisGeneratorTool implements Plugin {
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
.id("mybatisgenerator")
.name("MyBatis逆向工程")
.version("1.0.0")
.description("根据数据库表结构生成PO/Mapper/XML")
.build();
private static final String[] MENU_OPTIONS = {
"1. 根据表名生成(单表)",
@@ -30,13 +38,8 @@ public class MyBatisGeneratorTool implements Tool {
private final MyBatisGeneratorService generatorService;
@Override
public String getId() {
return "mybatisgenerator";
}
@Override
public String getName() {
return "MyBatis逆向工程";
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
@@ -1,7 +1,8 @@
package com.example.workutils.biz.scanner;
import com.example.workutils.biz.scanner.service.ScannerService;
import com.example.workutils.system.tool.Tool;
import com.example.workutils.system.plugin.Plugin;
import com.example.workutils.system.plugin.PluginDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -9,12 +10,19 @@ import org.springframework.stereotype.Component;
import java.util.Scanner;
/**
* 扫描工具入口(符合 Tool 规范)
* 扫描工具插件(实现 Plugin 接口)
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ScannerTool implements Tool {
public class ScannerTool implements Plugin {
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
.id("scan")
.name("扫描功能")
.version("1.0.0")
.description("关键词/Redis/Dubbo扫描工具")
.build();
private static final String[] MENU_OPTIONS = {
"1. 关键词扫描",
@@ -24,13 +32,8 @@ public class ScannerTool implements Tool {
private final ScannerService scannerService;
@Override
public String getId() {
return "scan";
}
@Override
public String getName() {
return "扫描功能";
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
@@ -0,0 +1,41 @@
package com.example.workutils.system.plugin;
import com.example.workutils.system.tool.Tool;
/**
* 插件接口 —— 所有 biz 模块的顶级契约
* <p>
* 继承 {@link Tool},在其基础上增加插件生命周期管理:
* <ul>
* <li>{@link #getDescriptor()} — 提供插件元数据(id/name/version/description/dependencies)</li>
* <li>{@link #onLoad(PluginContext)} — 插件加载时回调,注入运行时上下文</li>
* <li>{@link #onUnload()} — 插件卸载时回调,清理资源</li>
* </ul>
* <p>
* getId()/getName() 默认委托给 PluginDescriptor,实现类只需提供 getDescriptor()。
*/
public interface Plugin extends Tool {
/** 插件描述符(元数据) */
PluginDescriptor getDescriptor();
/** 插件加载回调,PluginManager 在注册时调用 */
default void onLoad(PluginContext context) {
}
/** 插件卸载回调,清理资源 */
default void onUnload() {
}
// ==================== 默认委托 ====================
@Override
default String getId() {
return getDescriptor().getId();
}
@Override
default String getName() {
return getDescriptor().getName();
}
}
@@ -0,0 +1,42 @@
package com.example.workutils.system.plugin;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 插件运行时上下文
* <p>
* 通过 {@link Plugin#onLoad(PluginContext)} 注入给每个插件,
* 提供访问 PluginManager 和跨插件共享属性的能力。
*/
public class PluginContext {
private final PluginManager pluginManager;
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
public PluginContext(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
/** 获取 PluginManager,用于插件间通信 */
public PluginManager getPluginManager() {
return pluginManager;
}
/** 设置共享属性 */
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
/** 获取共享属性 */
@SuppressWarnings("unchecked")
public <T> T getAttribute(String key) {
return (T) attributes.get(key);
}
/** 获取共享属性,带默认值 */
@SuppressWarnings("unchecked")
public <T> T getAttribute(String key, T defaultValue) {
return (T) attributes.getOrDefault(key, defaultValue);
}
}
@@ -0,0 +1,68 @@
package com.example.workutils.system.plugin;
import java.util.Collections;
import java.util.List;
/**
* 插件描述符(不可变元数据)
* <p>
* 每个 Plugin 通过 {@link Plugin#getDescriptor()} 返回此描述符,
* PluginManager 据此识别、管理、展示插件。
*/
public class PluginDescriptor {
private final String id;
private final String name;
private final String version;
private final String description;
private final List<String> dependencies;
private PluginDescriptor(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.version = builder.version;
this.description = builder.description;
this.dependencies = Collections.unmodifiableList(builder.dependencies);
}
public static Builder builder() {
return new Builder();
}
// ==================== Getters ====================
public String getId() { return id; }
public String getName() { return name; }
public String getVersion() { return version; }
public String getDescription() { return description; }
/** 依赖的插件 ID 列表(暂未强制校验,预留设计) */
public List<String> getDependencies() { return dependencies; }
@Override
public String toString() {
return name + " [v" + version + "]";
}
// ==================== Builder ====================
public static class Builder {
private String id;
private String name;
private String version = "1.0.0";
private String description = "";
private List<String> dependencies = Collections.emptyList();
public Builder id(String id) { this.id = id; return this; }
public Builder name(String name) { this.name = name; return this; }
public Builder version(String version) { this.version = version;return this; }
public Builder description(String desc) { this.description = desc; return this; }
public Builder dependencies(List<String> d) { this.dependencies = d; return this; }
public PluginDescriptor build() {
if (id == null || id.isEmpty()) throw new IllegalArgumentException("plugin id is required");
if (name == null || name.isEmpty()) throw new IllegalArgumentException("plugin name is required");
return new PluginDescriptor(this);
}
}
}
@@ -0,0 +1,255 @@
package com.example.workutils.system.plugin;
import com.example.workutils.system.config.WorkUtilsProperties;
import com.example.workutils.system.support.ConsoleHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.*;
/**
* 插件管理器 —— 插件生命周期管理 + 注册中心 + 主菜单
* <p>
* 替换旧版 {@code ToolRegistry},统一管理所有 {@link Plugin} 的:
* <ul>
* <li>生命周期 — load / unload / enable / disable</li>
* <li>注册发现 — 按 id / command 查找</li>
* <li>启用过滤 — 白名单 / 黑名单</li>
* <li>主菜单 — 交互式菜单循环</li>
* <li>命令行分发 — 按 command 名路由</li>
* </ul>
*/
@Slf4j
@Component
public class PluginManager {
private static final int EXIT_CODE = 0;
private final List<Plugin> allPlugins;
private final WorkUtilsProperties properties;
private PluginContext pluginContext;
private List<Plugin> enabledPlugins;
private Map<String, Plugin> pluginByIdMap;
private Map<String, Plugin> pluginByCommandMap;
private Map<String, PluginState> pluginStates;
public PluginManager(List<Plugin> plugins, WorkUtilsProperties properties) {
this.allPlugins = plugins;
this.properties = properties;
}
@PostConstruct
public void init() {
this.pluginContext = new PluginContext(this);
this.enabledPlugins = new ArrayList<>();
this.pluginByIdMap = new LinkedHashMap<>();
this.pluginByCommandMap = new LinkedHashMap<>();
this.pluginStates = new LinkedHashMap<>();
Set<String> enabledIds = resolveEnabledIds();
for (Plugin plugin : allPlugins) {
try {
// 生命周期:加载
plugin.onLoad(pluginContext);
PluginDescriptor desc = plugin.getDescriptor();
pluginStates.put(desc.getId(), PluginState.LOADED);
if (enabledIds == null || enabledIds.contains(desc.getId())) {
enabledPlugins.add(plugin);
pluginByIdMap.put(desc.getId(), plugin);
pluginStates.put(desc.getId(), PluginState.ACTIVE);
String cmd = plugin.getCommandName();
if (cmd != null && !cmd.isEmpty()) {
pluginByCommandMap.put(cmd, plugin);
}
log.info("加载插件: {}", desc);
} else {
pluginStates.put(desc.getId(), PluginState.DISABLED);
log.info("跳过已禁用插件: {}", desc);
}
} catch (Exception e) {
String pluginId = safeGetId(plugin);
pluginStates.put(pluginId, PluginState.ERROR);
log.error("插件加载失败: " + pluginId, e);
}
}
log.info("插件加载完成: {}/{} 已激活", enabledPlugins.size(), allPlugins.size());
}
// ==================== 主菜单 ====================
/** 启动主菜单交互循环 */
public void runMainMenu(Scanner scanner) {
log.info("启动主菜单");
while (true) {
ConsoleHelper.printMenuTitle("主菜单");
displayMainMenu();
int choice = ConsoleHelper.readChoice(scanner);
scanner.nextLine();
if (choice == EXIT_CODE) {
log.info("用户退出系统");
System.out.println("感谢使用,再见!");
shutdown();
break;
}
dispatchPlugin(choice, scanner);
}
}
private void displayMainMenu() {
System.out.println("请选择操作:");
for (int i = 0; i < enabledPlugins.size(); i++) {
PluginDescriptor desc = enabledPlugins.get(i).getDescriptor();
System.out.println((i + 1) + ". " + desc.getName() + " [v" + desc.getVersion() + "]");
}
System.out.println(EXIT_CODE + ". 退出系统");
}
private void dispatchPlugin(int choice, Scanner scanner) {
int index = choice - 1;
if (index >= 0 && index < enabledPlugins.size()) {
Plugin plugin = enabledPlugins.get(index);
PluginDescriptor desc = plugin.getDescriptor();
try {
plugin.execute(scanner);
} catch (Exception e) {
log.error("插件执行失败: " + desc, e);
System.out.println("插件执行失败: " + e.getMessage());
}
} else {
ConsoleHelper.printInvalidOption();
}
}
// ==================== 查找方法 ====================
/** 获取所有已启用插件(只读) */
public List<Plugin> getEnabledPlugins() {
return Collections.unmodifiableList(enabledPlugins);
}
/** 按 ID 查找插件 */
public Optional<Plugin> getPluginById(String id) {
return Optional.ofNullable(pluginByIdMap.get(id));
}
/** 按命令行命令名查找插件 */
public Optional<Plugin> getPluginByCommand(String command) {
return Optional.ofNullable(pluginByCommandMap.get(command));
}
/** 获取插件状态 */
public PluginState getPluginState(String pluginId) {
return pluginStates.getOrDefault(pluginId, PluginState.UNLOADED);
}
/** 列出所有插件(含已禁用) */
public List<PluginDescriptor> listAllPluginDescriptors() {
List<PluginDescriptor> result = new ArrayList<>();
for (Plugin plugin : allPlugins) {
result.add(plugin.getDescriptor());
}
return result;
}
// ==================== 生命周期管理(预留) ====================
/** 手动启用插件 */
public boolean enablePlugin(String pluginId) {
Plugin plugin = pluginByIdMap.get(pluginId);
if (plugin == null) {
Plugin p = findPluginById(pluginId);
if (p == null) {
log.warn("未找到插件: {}", pluginId);
return false;
}
enabledPlugins.add(p);
pluginByIdMap.put(pluginId, p);
String cmd = p.getCommandName();
if (cmd != null && !cmd.isEmpty()) {
pluginByCommandMap.put(cmd, p);
}
pluginStates.put(pluginId, PluginState.ACTIVE);
log.info("启用插件: {}", p.getDescriptor());
} else {
pluginStates.put(pluginId, PluginState.ACTIVE);
}
return true;
}
/** 手动禁用插件 */
public boolean disablePlugin(String pluginId) {
Plugin plugin = pluginByIdMap.remove(pluginId);
if (plugin != null) {
enabledPlugins.remove(plugin);
String cmd = plugin.getCommandName();
if (cmd != null && !cmd.isEmpty()) {
pluginByCommandMap.remove(cmd, plugin);
}
pluginStates.put(pluginId, PluginState.DISABLED);
log.info("禁用插件: {}", plugin.getDescriptor());
}
return plugin != null;
}
// ==================== 内部方法 ====================
private void shutdown() {
for (Plugin plugin : allPlugins) {
try {
plugin.onUnload();
} catch (Exception e) {
log.warn("插件卸载异常: " + plugin.getDescriptor(), e);
}
}
}
private Plugin findPluginById(String id) {
for (Plugin p : allPlugins) {
if (p.getId().equals(id)) {
return p;
}
}
return null;
}
private String safeGetId(Plugin plugin) {
try {
return plugin.getId();
} catch (Exception e) {
return "unknown";
}
}
// ==================== 启用/禁用解析 ====================
private Set<String> resolveEnabledIds() {
WorkUtilsProperties.ToolsConfig toolsConfig = properties.getTools();
if (toolsConfig == null) {
return null;
}
if (toolsConfig.getEnabled() != null && !toolsConfig.getEnabled().isEmpty()) {
return new HashSet<>(toolsConfig.getEnabled());
}
if (toolsConfig.getDisabled() != null && !toolsConfig.getDisabled().isEmpty()) {
Set<String> allIds = new HashSet<>();
for (Plugin plugin : allPlugins) {
allIds.add(plugin.getId());
}
allIds.removeAll(toolsConfig.getDisabled());
return allIds;
}
return null;
}
}
@@ -0,0 +1,22 @@
package com.example.workutils.system.plugin;
/**
* 插件生命周期状态
*/
public enum PluginState {
/** 未加载 */
UNLOADED,
/** 已加载(onLoad 完成) */
LOADED,
/** 已激活(已启用,可交互) */
ACTIVE,
/** 已禁用 */
DISABLED,
/** 加载/执行异常 */
ERROR
}
@@ -1,142 +0,0 @@
package com.example.workutils.system.tool;
import com.example.workutils.system.support.ConsoleHelper;
import com.example.workutils.system.config.WorkUtilsProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 工具注册中心
* 自动发现 Spring 容器中的 Tool Bean,按配置过滤启用/禁用
* 同时负责主菜单循环
*/
@Slf4j
@Component
public class ToolRegistry {
private static final int EXIT_CODE = 0;
private final List<Tool> allTools;
private final WorkUtilsProperties properties;
private List<Tool> enabledTools;
private Map<String, Tool> toolByIdMap;
private Map<String, Tool> toolByCommandMap;
public ToolRegistry(List<Tool> tools, WorkUtilsProperties properties) {
this.allTools = tools;
this.properties = properties;
}
@PostConstruct
public void init() {
Set<String> enabledIds = resolveEnabledIds();
this.enabledTools = new ArrayList<>();
this.toolByIdMap = new LinkedHashMap<>();
this.toolByCommandMap = new LinkedHashMap<>();
for (Tool tool : allTools) {
try {
if (enabledIds == null || enabledIds.contains(tool.getId())) {
enabledTools.add(tool);
toolByIdMap.put(tool.getId(), tool);
String cmd = tool.getCommandName();
if (cmd != null && !cmd.isEmpty()) {
toolByCommandMap.put(cmd, tool);
}
log.info("注册工具: {} [{}]", tool.getName(), tool.getId());
} else {
log.info("跳过已禁用工具: {} [{}]", tool.getName(), tool.getId());
}
} catch (Exception e) {
log.error("工具初始化失败: {} [{}]", tool.getName(), tool.getId(), e);
}
}
log.info("工具注册完成: {}/{} 已启用", enabledTools.size(), allTools.size());
}
// ==================== 主菜单 ====================
public void runMainMenu(Scanner scanner) {
log.info("启动主菜单");
while (true) {
ConsoleHelper.printMenuTitle("主菜单");
displayMainMenu();
int choice = ConsoleHelper.readChoice(scanner);
scanner.nextLine();
if (choice == EXIT_CODE) {
log.info("用户退出系统");
System.out.println("感谢使用,再见!");
break;
}
dispatchTool(choice, scanner);
}
}
private void displayMainMenu() {
System.out.println("请选择操作:");
for (int i = 0; i < enabledTools.size(); i++) {
System.out.println((i + 1) + ". " + enabledTools.get(i).getName());
}
System.out.println(EXIT_CODE + ". 退出系统");
}
private void dispatchTool(int choice, Scanner scanner) {
int index = choice - 1;
if (index >= 0 && index < enabledTools.size()) {
Tool tool = enabledTools.get(index);
try {
tool.execute(scanner);
} catch (Exception e) {
log.error("工具执行失败: {} [{}]", tool.getName(), tool.getId(), e);
System.out.println("工具执行失败: " + e.getMessage());
}
} else {
ConsoleHelper.printInvalidOption();
}
}
// ==================== 查找方法 ====================
public List<Tool> getEnabledTools() {
return Collections.unmodifiableList(enabledTools);
}
public Optional<Tool> getToolById(String id) {
return Optional.ofNullable(toolByIdMap.get(id));
}
public Optional<Tool> getToolByCommand(String command) {
return Optional.ofNullable(toolByCommandMap.get(command));
}
// ==================== 启用/禁用解析 ====================
private Set<String> resolveEnabledIds() {
WorkUtilsProperties.ToolsConfig toolsConfig = properties.getTools();
if (toolsConfig == null) {
return null;
}
if (toolsConfig.getEnabled() != null && !toolsConfig.getEnabled().isEmpty()) {
return new HashSet<>(toolsConfig.getEnabled());
}
if (toolsConfig.getDisabled() != null && !toolsConfig.getDisabled().isEmpty()) {
Set<String> allIds = allTools.stream()
.map(Tool::getId)
.collect(Collectors.toSet());
allIds.removeAll(toolsConfig.getDisabled());
return allIds;
}
return null;
}
}