From 484c84d6e22778d8452db4dbc757c777f1e7958d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=B6=E8=AE=AD?= Date: Fri, 5 Jun 2026 14:12:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generator.rar | Bin 0 -> 2978 bytes .../workutils/WorkUtilsAppliction.java | 127 +------------- .../workutils/config/WorkUtilsProperties.java | 22 +++ .../example/workutils/menu/api/MenuItem.java | 66 ------- .../workutils/menu/api/MenuRunner.java | 165 +++++------------- .../menu/handler/AbstractMenuHandler.java | 116 ------------ .../workutils/menu/handler/BatchHandler.java | 89 +++------- .../menu/handler/GitHealthHandler.java | 100 +++-------- .../menu/handler/MyBatisGeneratorHandler.java | 116 +++--------- .../menu/handler/MyBatisHandler.java | 107 +++--------- .../workutils/menu/handler/ScanHandler.java | 68 ++------ .../workutils/menu/model/MenuGroup.java | 68 -------- .../workutils/menu/model/MenuItem.java | 30 ---- .../example/workutils/tool/AbstractTool.java | 97 ++++++++++ .../java/com/example/workutils/tool/Tool.java | 35 ++++ .../example/workutils/tool/ToolRegistry.java | 97 ++++++++++ src/main/resources/application.yml | 14 ++ 17 files changed, 428 insertions(+), 889 deletions(-) create mode 100644 generator.rar delete mode 100644 src/main/java/com/example/workutils/menu/api/MenuItem.java delete mode 100644 src/main/java/com/example/workutils/menu/handler/AbstractMenuHandler.java delete mode 100644 src/main/java/com/example/workutils/menu/model/MenuGroup.java delete mode 100644 src/main/java/com/example/workutils/menu/model/MenuItem.java create mode 100644 src/main/java/com/example/workutils/tool/AbstractTool.java create mode 100644 src/main/java/com/example/workutils/tool/Tool.java create mode 100644 src/main/java/com/example/workutils/tool/ToolRegistry.java diff --git a/generator.rar b/generator.rar new file mode 100644 index 0000000000000000000000000000000000000000..29a7f88729eb613f9f8b5bbb49e4fef9bd8bb441 GIT binary patch literal 2978 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 L$U9U(YQVn%B;;iw literal 0 HcmV?d00001 diff --git a/src/main/java/com/example/workutils/WorkUtilsAppliction.java b/src/main/java/com/example/workutils/WorkUtilsAppliction.java index 054f5ed..aabd1b7 100644 --- a/src/main/java/com/example/workutils/WorkUtilsAppliction.java +++ b/src/main/java/com/example/workutils/WorkUtilsAppliction.java @@ -1,13 +1,10 @@ package com.example.workutils; -import com.example.workutils.config.WorkUtilsProperties; -import com.example.workutils.menu.api.MenuRunner; -import com.example.workutils.menu.handler.GitHealthHandler; import com.example.workutils.biz.mybatis.export.MyBatisExportService; import com.example.workutils.biz.scanner.service.ScanService; -import com.example.workutils.biz.git.service.GitService; +import com.example.workutils.menu.api.MenuRunner; +import com.example.workutils.tool.ToolRegistry; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -24,24 +21,18 @@ import java.util.Scanner; @Slf4j public class WorkUtilsAppliction implements CommandLineRunner { + @Autowired + private MenuRunner menuRunner; + + @Autowired + private ToolRegistry toolRegistry; + @Autowired private MyBatisExportService myBatisExportService; @Autowired private ScanService scanService; - @Autowired - private GitService gitService; - - @Autowired - private MenuRunner menuRunner; - - @Autowired - private GitHealthHandler gitHealthHandler; - - @Autowired - private WorkUtilsProperties properties; - public static void main(String[] args) { SpringApplication.run(WorkUtilsAppliction.class, args); } @@ -86,11 +77,9 @@ public class WorkUtilsAppliction implements CommandLineRunner { if (args.length > 1) { String subCommand = args[1].toLowerCase(); if ("table".equals(subCommand) && args.length > 2) { - // Export SQL by table name myBatisExportService.exportSQLByTable(args[2]); System.out.println("表名SQL导出完成!"); } else if ("tables".equals(subCommand) && args.length > 2) { - // Export SQL by multiple table names List tableNames = new ArrayList<>(); for (int i = 2; i < args.length; i++) { tableNames.add(args[i]); @@ -98,12 +87,10 @@ public class WorkUtilsAppliction implements CommandLineRunner { myBatisExportService.exportSQLByTables(tableNames); System.out.println("多表SQL导出完成!"); } else { - // Default: export all SQL myBatisExportService.exportSQL(); System.out.println("所有SQL导出完成!"); } } else { - // Default: export all SQL myBatisExportService.exportSQL(); System.out.println("所有SQL导出完成!"); } @@ -137,102 +124,6 @@ public class WorkUtilsAppliction implements CommandLineRunner { System.out.println("扫描完成,结果已保存到:" + outputFile); } - private void handleGitManagement(Scanner scanner) { - while (true) { - System.out.println("\n=== Git管理 ==="); - System.out.println("1. 切换并拉取最新代码"); - System.out.println("2. 检查分支变更情况"); - System.out.println("3. Git仓库健康检测"); - System.out.println("0. 返回上级菜单"); - System.out.print("请选择选项:"); - - try { - int choice = scanner.nextInt(); - scanner.nextLine(); // 消费换行符 - - switch (choice) { - case 1: - handleGitCheckoutAndPull(scanner); - break; - case 2: - handleCheckBranchChanges(scanner); - break; - case 3: - gitHealthHandler.execute(scanner); - break; - case 0: - return; - default: - System.out.println("无效选项,请重新选择。"); - } - } catch (Exception e) { - log.error("Git管理操作失败", e); - System.out.println("操作失败:" + e.getMessage()); - scanner.nextLine(); // 清除错误输入 - } - } - } - - private void handleCheckBranchChanges(Scanner scanner) { - System.out.println("\n=== 检查分支变更情况 ==="); - System.out.print("请输入仓库根目录路径(默认:D:\\bestpay-srdcould):"); - String repoRoot = scanner.nextLine().trim(); - if (StringUtils.isBlank(repoRoot)) { - repoRoot = "D:/bestpay-srdcloud"; - } - - System.out.println("可用的分支对配置:"); - System.out.println("1. origin/DEV-XQYFGL-96408,origin/SIT-20240829"); - System.out.println("2. origin/DEV_XQYFGL96408,origin/SIT-20240829"); - System.out.println("3. origin/SIT-20240829,origin/master"); - System.out.print("请选择或输入自定义分支对 (格式: 源分支,目标分支):"); - String branchPairsInput = scanner.nextLine().trim(); - - String branchPairs; - switch (branchPairsInput) { - case "1": - branchPairs = "origin/DEV-XQYFGL-96408,origin/SIT-20240829"; - break; - case "2": - branchPairs = "origin/DEV_XQYFGL96408,origin/SIT-20240829"; - break; - case "3": - branchPairs = "origin/SIT-20240829,origin/master"; - break; - default: - branchPairs = branchPairsInput; - break; - } - - if (branchPairs.isEmpty()) { - System.out.println("未提供分支对信息,操作取消。"); - return; - } - - System.out.println("正在执行检查,请稍候..."); - gitService.checkBranchChanges(repoRoot, branchPairs); - } - - private void handleGitCheckoutAndPull(Scanner scanner) { - System.out.println("\n=== 切换并拉取最新代码 ==="); - System.out.print("请输入仓库根目录路径(默认:D:\\bestpay-srdcould):"); - String repoRoot = scanner.nextLine().trim(); - if (StringUtils.isBlank(repoRoot)) { - repoRoot = "D:/bestpay-srdcloud"; - } - - System.out.print("请输入要拉取的分支名称:(默认:master):"); - String targetBranch = scanner.nextLine().trim(); - - if (targetBranch.isEmpty()) { - targetBranch = "master"; - } - - System.out.println("正在执行分支切换和拉取,请稍候..."); - gitService.checkoutAndPull(repoRoot, targetBranch); - } - - private void showUsage() { System.out.println("WorkUtils 使用说明:"); System.out.println(""); @@ -249,4 +140,4 @@ public class WorkUtilsAppliction implements CommandLineRunner { System.out.println(" java -jar workutils.jar scan keyword \"TODO\" # 扫描TODO关键词"); System.out.println(" java -jar workutils.jar batch # 执行所有检查"); } -} \ No newline at end of file +} diff --git a/src/main/java/com/example/workutils/config/WorkUtilsProperties.java b/src/main/java/com/example/workutils/config/WorkUtilsProperties.java index 7b6c12f..2fcf418 100644 --- a/src/main/java/com/example/workutils/config/WorkUtilsProperties.java +++ b/src/main/java/com/example/workutils/config/WorkUtilsProperties.java @@ -9,6 +9,7 @@ import java.nio.file.Paths; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.List; /** * 工具集配置属性 @@ -34,6 +35,9 @@ public class WorkUtilsProperties { /** 项目路径配置文件名 */ private String projectPathsFile = "代码仓库项目路径.txt"; + /** 工具启用/禁用配置 */ + private ToolsConfig tools; + /** 日期格式:yyyyMMdd */ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); @@ -105,4 +109,22 @@ public class WorkUtilsProperties { String fileName = generateExportFileName(prefix, extension); return getTodayExportPath().resolve(fileName); } + + /** + * 工具启用/禁用配置 + */ + @Data + public static class ToolsConfig { + /** + * 启用的工具ID列表,设置后仅加载这些工具 + * 示例: ["scan", "mybatis", "batch", "git-health", "mybatis-generator"] + */ + private List enabled; + + /** + * 禁用的工具ID列表,设置后排除这些工具 + * enabled优先级高于disabled + */ + private List disabled; + } } diff --git a/src/main/java/com/example/workutils/menu/api/MenuItem.java b/src/main/java/com/example/workutils/menu/api/MenuItem.java deleted file mode 100644 index ff59203..0000000 --- a/src/main/java/com/example/workutils/menu/api/MenuItem.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.workutils.menu.api; - -import com.example.workutils.menu.handler.AbstractMenuHandler; -import com.example.workutils.menu.handler.BatchHandler; -import com.example.workutils.menu.handler.GitHealthHandler; -import com.example.workutils.menu.handler.MyBatisGeneratorHandler; -import com.example.workutils.menu.handler.MyBatisHandler; -import com.example.workutils.menu.handler.ScanHandler; - -/** - * 菜单项枚举 - * 统一管理菜单序号、名称和处理器 - */ -public enum MenuItem { - SCAN(1, "关键词扫描", ScanHandler.class), - MYBATIS(2, "MyBatis导出", MyBatisHandler.class), - BATCH(3, "批量处理", BatchHandler.class), - GIT_HEALTH(4, "Git仓库健康检测", GitHealthHandler.class), - MYBATIS_GENERATOR(5, "MyBatis逆向工程", MyBatisGeneratorHandler.class), - EXIT(0, "退出系统", null); - - private final int code; - private final String name; - private final Class handlerClass; - - MenuItem(int code, String name, Class handlerClass) { - this.code = code; - this.name = name; - this.handlerClass = handlerClass; - } - - public int getCode() { - return code; - } - - public String getName() { - return name; - } - - public String getDisplayText() { - return code + ". " + name; - } - - public Class getHandlerClass() { - return handlerClass; - } - - public boolean hasHandler() { - return handlerClass != null; - } - - /** - * 根据序号获取菜单项 - * - * @param code 菜单序号 - * @return 菜单项,未找到返回null - */ - public static MenuItem fromCode(int code) { - for (MenuItem item : values()) { - if (item.code == code) { - return item; - } - } - return null; - } -} diff --git a/src/main/java/com/example/workutils/menu/api/MenuRunner.java b/src/main/java/com/example/workutils/menu/api/MenuRunner.java index 2176570..d1727a4 100644 --- a/src/main/java/com/example/workutils/menu/api/MenuRunner.java +++ b/src/main/java/com/example/workutils/menu/api/MenuRunner.java @@ -1,101 +1,42 @@ package com.example.workutils.menu.api; -import com.example.workutils.menu.handler.AbstractMenuHandler; -import com.example.workutils.menu.handler.BatchHandler; -import com.example.workutils.menu.handler.GitHealthHandler; -import com.example.workutils.menu.handler.MyBatisGeneratorHandler; -import com.example.workutils.menu.handler.MyBatisHandler; -import com.example.workutils.menu.handler.ScanHandler; +import com.example.workutils.tool.Tool; +import com.example.workutils.tool.ToolRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.Map; +import java.util.List; import java.util.Scanner; /** * 菜单运行器 - * 统一管理菜单注册和执行 + * 从ToolRegistry动态构建主菜单,无需硬编码Handler引用 */ @Slf4j @Component public class MenuRunner { - /** - * 菜单处理器映射 (序号 -> 处理器) - */ - private final Map handlerMap = new HashMap<>(); + private static final int EXIT_CODE = 0; - /** - * 处理器实例映射 (类 -> 实例) - */ - private final Map, AbstractMenuHandler> handlerInstanceMap = new HashMap<>(); + private final ToolRegistry toolRegistry; - private final ScanHandler scanHandler; - private final MyBatisHandler myBatisHandler; - private final BatchHandler batchHandler; - private final GitHealthHandler gitHealthHandler; - private final MyBatisGeneratorHandler myBatisGeneratorHandler; - - public MenuRunner(ScanHandler scanHandler, - MyBatisHandler myBatisHandler, - BatchHandler batchHandler, - GitHealthHandler gitHealthHandler, - MyBatisGeneratorHandler myBatisGeneratorHandler) { - this.scanHandler = scanHandler; - this.myBatisHandler = myBatisHandler; - this.batchHandler = batchHandler; - this.gitHealthHandler = gitHealthHandler; - this.myBatisGeneratorHandler = myBatisGeneratorHandler; - - // 初始化处理器实例映射 - initHandlerInstanceMap(); - // 注册菜单处理器 - registerHandlers(); + public MenuRunner(ToolRegistry toolRegistry) { + this.toolRegistry = toolRegistry; } /** - * 初始化处理器实例映射 - */ - private void initHandlerInstanceMap() { - handlerInstanceMap.put(ScanHandler.class, scanHandler); - handlerInstanceMap.put(MyBatisHandler.class, myBatisHandler); - handlerInstanceMap.put(BatchHandler.class, batchHandler); - handlerInstanceMap.put(GitHealthHandler.class, gitHealthHandler); - handlerInstanceMap.put(MyBatisGeneratorHandler.class, myBatisGeneratorHandler); - } - - /** - * 注册菜单处理器 - */ - private void registerHandlers() { - for (MenuItem item : MenuItem.values()) { - if (item.hasHandler()) { - AbstractMenuHandler handler = handlerInstanceMap.get(item.getHandlerClass()); - if (handler != null) { - handlerMap.put(item.getCode(), handler); - } - } - } - - info("菜单处理器注册完成"); - } - - /** - * 运行主菜单 - * - * @param scanner 控制台输入扫描器 + * 运行主菜单循环 */ public void run(Scanner scanner) { info("启动主菜单"); while (true) { printMenuTitle("主菜单"); - displayMenu(); + displayMainMenu(); int choice = readChoice(scanner); scanner.nextLine(); - if (choice == MenuItem.EXIT.getCode()) { + if (choice == EXIT_CODE) { info("用户退出系统"); System.out.println("感谢使用,再见!"); break; @@ -106,43 +47,38 @@ public class MenuRunner { } /** - * 处理用户选择 + * 动态构建主菜单 + */ + private void displayMainMenu() { + System.out.println("请选择操作:"); + List tools = toolRegistry.getEnabledTools(); + for (int i = 0; i < tools.size(); i++) { + System.out.println((i + 1) + ". " + tools.get(i).getName()); + } + System.out.println(EXIT_CODE + ". 退出系统"); + } + + /** + * 处理用户选择,工具隔离 + * 单个工具异常不影响平台和其他工具 */ private void handleChoice(int choice, Scanner scanner) { - AbstractMenuHandler handler = handlerMap.get(choice); - if (handler != null) { + List tools = toolRegistry.getEnabledTools(); + int index = choice - 1; + + if (index >= 0 && index < tools.size()) { + Tool tool = tools.get(index); try { - handler.execute(scanner); + tool.execute(scanner); } catch (Exception e) { - error("菜单执行异常", e); - printError(e.getMessage()); + log.error("工具执行失败: {} [{}]", tool.getName(), tool.getId(), e); + System.out.println("工具执行失败: " + e.getMessage()); } } else { - printInvalidOption(); + System.out.println("无效选项"); } } - /** - * 显示菜单标题 - */ - private void printMenuTitle(String title) { - System.out.println(); - System.out.println("========== " + title + " =========="); - } - - /** - * 显示菜单选项 - */ - private void displayMenu() { - System.out.println("请选择操作:"); - for (MenuItem item : MenuItem.values()) { - System.out.println(item.getDisplayText()); - } - } - - /** - * 读取用户选择 - */ private int readChoice(Scanner scanner) { try { System.out.print("请输入选项编号: "); @@ -152,35 +88,12 @@ public class MenuRunner { } } - /** - * 打印无效选项提示 - */ - private void printInvalidOption() { - System.out.println("无效选项"); + private void printMenuTitle(String title) { + System.out.println(); + System.out.println("========== " + title + " =========="); } - /** - * 打印错误信息 - */ - private void printError(String message) { - System.out.println("操作失败: " + message); - } - - /** - * 记录信息日志 - */ - private void info(String message, Object... args) { - if (args.length > 0) { - log.info(message, args); - } else { - log.info(message); - } - } - - /** - * 记录错误日志 - */ - private void error(String message, Exception e) { - log.error(message, e); + private void info(String message) { + log.info(message); } } diff --git a/src/main/java/com/example/workutils/menu/handler/AbstractMenuHandler.java b/src/main/java/com/example/workutils/menu/handler/AbstractMenuHandler.java deleted file mode 100644 index eea056a..0000000 --- a/src/main/java/com/example/workutils/menu/handler/AbstractMenuHandler.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.example.workutils.menu.handler; - -import lombok.extern.slf4j.Slf4j; - -import java.util.Scanner; - -/** - * 菜单处理器抽象基类 - * 所有菜单处理器需继承此类 - */ -@Slf4j -public abstract class AbstractMenuHandler { - - /** - * 执行菜单处理 - * 子类需实现此方法定义具体的菜单逻辑 - * - * @param scanner 控制台输入扫描器 - */ - public abstract void execute(Scanner scanner); - - /** - * 获取菜单组名称 - * - * @return 菜单组名称 - */ - public abstract String getMenuName(); - - /** - * 获取菜单选项数组 - * 子类需实现此方法返回菜单选项 - * - * @return 菜单选项字符串数组 - */ - public abstract String[] getMenuOptions(); - - /** - * 打印分隔线 - */ - protected void printSeparator() { - System.out.println(); - } - - /** - * 打印菜单标题 - * - * @param title 菜单标题 - */ - protected void printMenuTitle(String title) { - printSeparator(); - System.out.println("========== " + title + " =========="); - } - - /** - * 打印操作成功信息 - * - * @param operation 操作名称 - */ - protected void printSuccess(String operation) { - System.out.println(operation + "完成!"); - } - - /** - * 打印错误信息 - * - * @param message 错误消息 - */ - protected void printError(String message) { - System.out.println("操作失败: " + message); - } - - /** - * 打印无效选项提示 - */ - protected void printInvalidOption() { - System.out.println("无效选项"); - } - - /** - * 记录信息日志 - * - * @param message 日志消息 - */ - protected void info(String message) { - log.info(message); - } - - /** - * 记录信息日志(带参数) - * - * @param message 日志消息模板 - * @param args 参数 - */ - protected void info(String message, Object... args) { - log.info(message, args); - } - - /** - * 记录错误日志 - * - * @param message 错误消息 - */ - protected void error(String message) { - log.error(message); - } - - /** - * 记录错误日志及异常 - * - * @param message 错误消息 - * @param e 异常 - */ - protected void error(String message, Exception e) { - log.error(message, e); - } -} diff --git a/src/main/java/com/example/workutils/menu/handler/BatchHandler.java b/src/main/java/com/example/workutils/menu/handler/BatchHandler.java index 33a9165..6cf1a92 100644 --- a/src/main/java/com/example/workutils/menu/handler/BatchHandler.java +++ b/src/main/java/com/example/workutils/menu/handler/BatchHandler.java @@ -2,6 +2,7 @@ package com.example.workutils.menu.handler; import com.example.workutils.biz.mybatis.export.MyBatisExportService; import com.example.workutils.biz.scanner.service.ScanService; +import com.example.workutils.tool.AbstractTool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -11,16 +12,13 @@ import java.util.List; import java.util.Scanner; /** - * 批量处理功能处理器 + * 批量处理功能工具 */ @Slf4j @Component @RequiredArgsConstructor -public class BatchHandler extends AbstractMenuHandler { +public class BatchHandler extends AbstractTool { - /** - * 可执行异常的操作接口 - */ @FunctionalInterface public interface ExceptionRunnable { void run() throws Exception; @@ -43,7 +41,12 @@ public class BatchHandler extends AbstractMenuHandler { private final MyBatisExportService myBatisExportService; @Override - public String getMenuName() { + public String getId() { + return "batch"; + } + + @Override + public String getName() { return "批量处理"; } @@ -53,41 +56,20 @@ public class BatchHandler extends AbstractMenuHandler { } @Override - public void execute(Scanner scanner) { - while (true) { - printMenuTitle(getMenuName()); - displayMenu(getMenuOptions()); - - int choice = readChoice(scanner); - scanner.nextLine(); - - if (choice == 0) { - info("返回上级菜单"); - return; - } - - try { - switch (choice) { - case 1: - executeAllChecks(); - break; - case 2: - executeCustomChecks(scanner); - break; - default: - printInvalidOption(); - break; - } - } catch (Exception e) { - error("批量处理操作失败", e); - printError(e.getMessage()); - } + protected void handleChoice(int choice, Scanner scanner) throws Exception { + switch (choice) { + case 1: + executeAllChecks(); + break; + case 2: + executeCustomChecks(scanner); + break; + default: + printInvalidOption(); + break; } } - /** - * 执行所有检查 - */ private void executeAllChecks() throws Exception { printMenuTitle("执行所有检查"); info("开始执行所有检查"); @@ -102,9 +84,6 @@ public class BatchHandler extends AbstractMenuHandler { info("所有检查执行完成"); } - /** - * 执行自定义检查 - */ private void executeCustomChecks(Scanner scanner) throws Exception { printMenuTitle("自定义组合检查"); displayMenu(CUSTOM_CHECK_OPTIONS); @@ -147,17 +126,11 @@ public class BatchHandler extends AbstractMenuHandler { printSuccess("自定义检查"); } - /** - * 执行单个步骤 - */ private void executeStep(String stepName, ExceptionRunnable action) throws Exception { System.out.println(stepName); action.run(); } - /** - * 解析逗号分隔的输入 - */ private List parseCommaSeparatedInput(String input) { List result = new ArrayList<>(); if (input == null || input.trim().isEmpty()) { @@ -172,26 +145,4 @@ public class BatchHandler extends AbstractMenuHandler { } return result; } - - /** - * 显示菜单选项 - */ - private void displayMenu(String[] options) { - System.out.println("请选择操作:"); - for (String option : options) { - System.out.println(option); - } - } - - /** - * 读取用户选择 - */ - private int readChoice(Scanner scanner) { - try { - System.out.print("请输入选项编号: "); - return scanner.nextInt(); - } catch (Exception e) { - return -1; - } - } } diff --git a/src/main/java/com/example/workutils/menu/handler/GitHealthHandler.java b/src/main/java/com/example/workutils/menu/handler/GitHealthHandler.java index 9b953b6..3aefb8c 100644 --- a/src/main/java/com/example/workutils/menu/handler/GitHealthHandler.java +++ b/src/main/java/com/example/workutils/menu/handler/GitHealthHandler.java @@ -2,6 +2,7 @@ package com.example.workutils.menu.handler; import com.example.workutils.biz.git.service.GitService; import com.example.workutils.biz.git.util.GitCommandExecutor; +import com.example.workutils.tool.AbstractTool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -12,12 +13,12 @@ import java.util.Scanner; import java.util.stream.Collectors; /** - * Git仓库健康检测处理器 + * Git仓库健康检测工具 */ @Slf4j @Component @RequiredArgsConstructor -public class GitHealthHandler extends AbstractMenuHandler { +public class GitHealthHandler extends AbstractTool { private static final String[] MENU_OPTIONS = { "1. 检测所有仓库健康状态", @@ -28,7 +29,12 @@ public class GitHealthHandler extends AbstractMenuHandler { private final GitService gitService; @Override - public String getMenuName() { + public String getId() { + return "git-health"; + } + + @Override + public String getName() { return "Git仓库健康检测"; } @@ -38,41 +44,20 @@ public class GitHealthHandler extends AbstractMenuHandler { } @Override - public void execute(Scanner scanner) { - while (true) { - printMenuTitle(getMenuName()); - displayMenu(getMenuOptions()); - - int choice = readChoice(scanner); - scanner.nextLine(); - - if (choice == 0) { - info("返回上级菜单"); - return; - } - - try { - switch (choice) { - case 1: - checkAllReposHealth(scanner); - break; - case 2: - fixCorruptedRepos(scanner); - break; - default: - printInvalidOption(); - break; - } - } catch (Exception e) { - error("Git仓库健康检测操作失败", e); - printError(e.getMessage()); - } + protected void handleChoice(int choice, Scanner scanner) throws Exception { + switch (choice) { + case 1: + checkAllReposHealth(scanner); + break; + case 2: + fixCorruptedRepos(scanner); + break; + default: + printInvalidOption(); + break; } } - /** - * 检测所有仓库健康状态 - */ private void checkAllReposHealth(Scanner scanner) { printMenuTitle("开始检测所有仓库"); info("开始检测所有仓库健康状态"); @@ -94,9 +79,6 @@ public class GitHealthHandler extends AbstractMenuHandler { } } - /** - * 修复损坏仓库 - */ private void fixCorruptedRepos(Scanner scanner) { List corruptedRepos = gitService.listCorruptedRepos(); @@ -106,13 +88,11 @@ public class GitHealthHandler extends AbstractMenuHandler { return; } - // 显示损坏仓库列表 printMenuTitle("损坏仓库列表"); for (int i = 0; i < corruptedRepos.size(); i++) { System.out.printf("[%d] %s%n", i + 1, corruptedRepos.get(i)); } - // 获取用户输入 System.out.print("\n请输入要修复的仓库序号(多个用逗号分隔,如1,2,3,输入a修复全部): "); String input = scanner.nextLine().trim(); @@ -123,7 +103,6 @@ public class GitHealthHandler extends AbstractMenuHandler { return; } - // 确认修复 System.out.print("确认修复 " + selectedIndices.size() + " 个仓库?(y/n): "); String confirm = scanner.nextLine().trim(); if (!"y".equalsIgnoreCase(confirm)) { @@ -132,7 +111,6 @@ public class GitHealthHandler extends AbstractMenuHandler { return; } - // 执行修复 info("开始修复 {} 个仓库", selectedIndices.size()); int successCount = 0; int failCount = 0; @@ -156,13 +134,6 @@ public class GitHealthHandler extends AbstractMenuHandler { info("修复完成,成功: {},失败: {}", successCount, failCount); } - /** - * 解析用户选择的仓库序号 - * - * @param input 用户输入 - * @param repoCount 仓库总数 - * @return 选择的序号列表 - */ private List parseSelectedIndices(String input, int repoCount) { if ("a".equalsIgnoreCase(input)) { List indices = new ArrayList<>(); @@ -184,12 +155,6 @@ public class GitHealthHandler extends AbstractMenuHandler { .collect(Collectors.toList()); } - /** - * 解析逗号分隔的输入 - * - * @param input 逗号分隔的字符串 - * @return 解析后的字符串列表 - */ private List parseCommaSeparatedInput(String input) { List result = new ArrayList<>(); if (input == null || input.trim().isEmpty()) { @@ -205,9 +170,6 @@ public class GitHealthHandler extends AbstractMenuHandler { return result; } - /** - * 从路径中提取项目名称 - */ private String extractProjectName(String projectPath) { if (projectPath == null || projectPath.isEmpty()) { return "unknown"; @@ -215,26 +177,4 @@ public class GitHealthHandler extends AbstractMenuHandler { int lastSep = Math.max(projectPath.lastIndexOf('/'), projectPath.lastIndexOf('\\')); return lastSep >= 0 ? projectPath.substring(lastSep + 1) : projectPath; } - - /** - * 显示菜单选项 - */ - private void displayMenu(String[] options) { - System.out.println("请选择操作:"); - for (String option : options) { - System.out.println(option); - } - } - - /** - * 读取用户选择 - */ - private int readChoice(Scanner scanner) { - try { - System.out.print("请输入选项编号: "); - return scanner.nextInt(); - } catch (Exception e) { - return -1; - } - } } diff --git a/src/main/java/com/example/workutils/menu/handler/MyBatisGeneratorHandler.java b/src/main/java/com/example/workutils/menu/handler/MyBatisGeneratorHandler.java index 8cbf2f8..c9f07ce 100644 --- a/src/main/java/com/example/workutils/menu/handler/MyBatisGeneratorHandler.java +++ b/src/main/java/com/example/workutils/menu/handler/MyBatisGeneratorHandler.java @@ -1,6 +1,7 @@ package com.example.workutils.menu.handler; import com.example.workutils.biz.mybatis.generator.MyBatisGeneratorService; +import com.example.workutils.tool.AbstractTool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -10,13 +11,12 @@ import java.util.List; import java.util.Scanner; /** - * MyBatis逆向工程菜单处理器 - * 用于根据数据库表结构生成Mapper文件 + * MyBatis逆向工程工具 */ @Slf4j @Component @RequiredArgsConstructor -public class MyBatisGeneratorHandler extends AbstractMenuHandler { +public class MyBatisGeneratorHandler extends AbstractTool { private static final String[] MENU_OPTIONS = { "1. 根据表名生成(单表)", @@ -30,7 +30,12 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { private final MyBatisGeneratorService generatorService; @Override - public String getMenuName() { + public String getId() { + return "mybatis-generator"; + } + + @Override + public String getName() { return "MyBatis逆向工程"; } @@ -40,50 +45,29 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { } @Override - public void execute(Scanner scanner) { - while (true) { - printMenuTitle(getMenuName()); - displayMenu(getMenuOptions()); - - int choice = readChoice(scanner); - scanner.nextLine(); - - if (choice == 0) { - info("返回上级菜单"); - return; - } - - try { - switch (choice) { - case 1: - generateBySingleTable(scanner); - break; - case 2: - generateByMultipleTables(scanner); - break; - case 3: - generateByPattern(scanner); - break; - case 4: - showAllTables(); - break; - case 5: - showConfiguration(); - break; - default: - printInvalidOption(); - break; - } - } catch (Exception e) { - error("逆向工程执行失败", e); - printError(e.getMessage()); - } + protected void handleChoice(int choice, Scanner scanner) throws Exception { + switch (choice) { + case 1: + generateBySingleTable(scanner); + break; + case 2: + generateByMultipleTables(scanner); + break; + case 3: + generateByPattern(scanner); + break; + case 4: + showAllTables(); + break; + case 5: + showConfiguration(); + break; + default: + printInvalidOption(); + break; } } - /** - * 根据单表名生成 - */ private void generateBySingleTable(Scanner scanner) throws Exception { System.out.print("请输入表名: "); String tableName = scanner.nextLine().trim(); @@ -99,9 +83,6 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { printSuccess("生成完成"); } - /** - * 根据多表名生成 - */ private void generateByMultipleTables(Scanner scanner) throws Exception { System.out.print("请输入表名(多个用逗号分隔): "); String input = scanner.nextLine().trim(); @@ -112,7 +93,6 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { } List tableNames = Arrays.asList(input.split(",")); - // 去除空格 for (int i = 0; i < tableNames.size(); i++) { tableNames.set(i, tableNames.get(i).trim()); } @@ -123,9 +103,6 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { printSuccess("生成完成"); } - /** - * 根据通配符生成 - */ private void generateByPattern(Scanner scanner) throws Exception { System.out.print("请输入表名通配符(如 user_%): "); String pattern = scanner.nextLine().trim(); @@ -135,20 +112,17 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { return; } - // 先查询匹配的表 List matchedTables = generatorService.queryTablesByPattern(pattern); if (matchedTables.isEmpty()) { System.out.println("未找到匹配通配符 [" + pattern + "] 的表"); return; } - // 展示匹配到的表 System.out.println("匹配到 " + matchedTables.size() + " 张表:"); for (int i = 0; i < matchedTables.size(); i++) { System.out.println(" " + (i + 1) + ". " + matchedTables.get(i)); } - // 确认是否继续 System.out.print("是否继续生成?(y/n): "); String confirm = scanner.nextLine().trim().toLowerCase(); if (!"y".equals(confirm)) { @@ -162,9 +136,6 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { printSuccess("生成完成"); } - /** - * 显示数据库中所有表 - */ private void showAllTables() throws Exception { List tables = generatorService.queryAllTables(); System.out.println(); @@ -175,9 +146,6 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { System.out.println("================================="); } - /** - * 显示当前配置信息 - */ private void showConfiguration() { System.out.println(); System.out.println("========== 当前配置信息 =========="); @@ -189,36 +157,10 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler { System.out.println("================================="); } - /** - * 遮蔽URL中的密码信息 - */ private String maskPassword(String url) { if (url == null) { return ""; } - // 简单处理,移除可能存在的密码参数 return url.replaceAll("password=[^&]*", "password=***"); } - - /** - * 显示菜单选项 - */ - private void displayMenu(String[] options) { - System.out.println("请选择操作:"); - for (String option : options) { - System.out.println(option); - } - } - - /** - * 读取用户选择 - */ - private int readChoice(Scanner scanner) { - try { - System.out.print("请输入选项编号: "); - return scanner.nextInt(); - } catch (Exception e) { - return -1; - } - } } diff --git a/src/main/java/com/example/workutils/menu/handler/MyBatisHandler.java b/src/main/java/com/example/workutils/menu/handler/MyBatisHandler.java index 0930309..a72e358 100644 --- a/src/main/java/com/example/workutils/menu/handler/MyBatisHandler.java +++ b/src/main/java/com/example/workutils/menu/handler/MyBatisHandler.java @@ -1,6 +1,7 @@ package com.example.workutils.menu.handler; import com.example.workutils.biz.mybatis.export.MyBatisExportService; +import com.example.workutils.tool.AbstractTool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -9,12 +10,12 @@ import java.util.Arrays; import java.util.Scanner; /** - * MyBatis导出功能处理器 + * MyBatis导出功能工具 */ @Slf4j @Component @RequiredArgsConstructor -public class MyBatisHandler extends AbstractMenuHandler { +public class MyBatisHandler extends AbstractTool { private static final String[] MENU_OPTIONS = { "1. 导出所有SQL", @@ -28,7 +29,12 @@ public class MyBatisHandler extends AbstractMenuHandler { private final MyBatisExportService myBatisExportService; @Override - public String getMenuName() { + public String getId() { + return "mybatis"; + } + + @Override + public String getName() { return "MyBatis SQL导出"; } @@ -38,50 +44,29 @@ public class MyBatisHandler extends AbstractMenuHandler { } @Override - public void execute(Scanner scanner) { - while (true) { - printMenuTitle(getMenuName()); - displayMenu(getMenuOptions()); - - int choice = readChoice(scanner); - scanner.nextLine(); - - if (choice == 0) { - info("返回上级菜单"); - return; - } - - try { - switch (choice) { - case 1: - exportAllSql(); - break; - case 2: - exportByTableName(scanner); - break; - case 3: - exportByTableNames(scanner); - break; - case 4: - exportByKeyword(scanner); - break; - case 5: - exportByTagId(scanner); - break; - default: - printInvalidOption(); - break; - } - } catch (Exception e) { - error("MyBatis导出执行失败", e); - printError(e.getMessage()); - } + protected void handleChoice(int choice, Scanner scanner) throws Exception { + switch (choice) { + case 1: + exportAllSql(); + break; + case 2: + exportByTableName(scanner); + break; + case 3: + exportByTableNames(scanner); + break; + case 4: + exportByKeyword(scanner); + break; + case 5: + exportByTagId(scanner); + break; + default: + printInvalidOption(); + break; } } - /** - * 导出所有SQL - */ private void exportAllSql() throws Exception { printMenuTitle("导出所有SQL"); info("开始导出所有SQL"); @@ -89,9 +74,6 @@ public class MyBatisHandler extends AbstractMenuHandler { printSuccess("导出所有SQL"); } - /** - * 按表名导出 - */ private void exportByTableName(Scanner scanner) throws Exception { System.out.print("请输入表名: "); String tableName = scanner.nextLine().trim(); @@ -104,9 +86,6 @@ public class MyBatisHandler extends AbstractMenuHandler { printSuccess("按表名导出SQL"); } - /** - * 按多个表名导出 - */ private void exportByTableNames(Scanner scanner) throws Exception { System.out.print("请输入表名(多个用逗号分隔): "); String tableNames = scanner.nextLine().trim(); @@ -119,9 +98,6 @@ public class MyBatisHandler extends AbstractMenuHandler { printSuccess("按多个表名导出SQL"); } - /** - * 按关键字导出 - */ private void exportByKeyword(Scanner scanner) throws Exception { System.out.print("请输入关键字: "); String keyword = scanner.nextLine().trim(); @@ -134,9 +110,6 @@ public class MyBatisHandler extends AbstractMenuHandler { printSuccess("按关键字导出SQL"); } - /** - * 按标签ID导出 - */ private void exportByTagId(Scanner scanner) throws Exception { System.out.print("请输入SQL标签ID: "); String tagId = scanner.nextLine().trim(); @@ -148,26 +121,4 @@ public class MyBatisHandler extends AbstractMenuHandler { myBatisExportService.exportSQLByTagId(tagId); printSuccess("按标签ID导出SQL"); } - - /** - * 显示菜单选项 - */ - private void displayMenu(String[] options) { - System.out.println("请选择操作:"); - for (String option : options) { - System.out.println(option); - } - } - - /** - * 读取用户选择 - */ - private int readChoice(Scanner scanner) { - try { - System.out.print("请输入选项编号: "); - return scanner.nextInt(); - } catch (Exception e) { - return -1; - } - } } diff --git a/src/main/java/com/example/workutils/menu/handler/ScanHandler.java b/src/main/java/com/example/workutils/menu/handler/ScanHandler.java index 4ed8ee2..cf5bb9f 100644 --- a/src/main/java/com/example/workutils/menu/handler/ScanHandler.java +++ b/src/main/java/com/example/workutils/menu/handler/ScanHandler.java @@ -1,6 +1,7 @@ package com.example.workutils.menu.handler; import com.example.workutils.biz.scanner.service.ScanService; +import com.example.workutils.tool.AbstractTool; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -8,12 +9,12 @@ import org.springframework.stereotype.Component; import java.util.Scanner; /** - * 扫描功能处理器 + * 扫描功能工具 */ @Slf4j @Component @RequiredArgsConstructor -public class ScanHandler extends AbstractMenuHandler { +public class ScanHandler extends AbstractTool { private static final String[] MENU_OPTIONS = { "1. 关键词扫描", @@ -23,7 +24,12 @@ public class ScanHandler extends AbstractMenuHandler { private final ScanService scanService; @Override - public String getMenuName() { + public String getId() { + return "scan"; + } + + @Override + public String getName() { return "扫描功能"; } @@ -33,32 +39,14 @@ public class ScanHandler extends AbstractMenuHandler { } @Override - public void execute(Scanner scanner) { - while (true) { - printMenuTitle(getMenuName()); - displayMenu(getMenuOptions()); - - int choice = readChoice(scanner); - scanner.nextLine(); - - if (choice == 0) { - info("返回上级菜单"); - return; - } - - try { - switch (choice) { - case 1: - scanByKeyword(scanner); - break; - default: - printInvalidOption(); - break; - } - } catch (Exception e) { - error("扫描功能执行失败", e); - printError(e.getMessage()); - } + protected void handleChoice(int choice, Scanner scanner) throws Exception { + switch (choice) { + case 1: + scanByKeyword(scanner); + break; + default: + printInvalidOption(); + break; } } @@ -82,26 +70,4 @@ public class ScanHandler extends AbstractMenuHandler { printSuccess("关键词扫描"); } - - /** - * 显示菜单选项 - */ - private void displayMenu(String[] options) { - System.out.println("请选择操作:"); - for (String option : options) { - System.out.println(option); - } - } - - /** - * 读取用户选择 - */ - private int readChoice(Scanner scanner) { - try { - System.out.print("请输入选项编号: "); - return scanner.nextInt(); - } catch (Exception e) { - return -1; - } - } } diff --git a/src/main/java/com/example/workutils/menu/model/MenuGroup.java b/src/main/java/com/example/workutils/menu/model/MenuGroup.java deleted file mode 100644 index e8058a6..0000000 --- a/src/main/java/com/example/workutils/menu/model/MenuGroup.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.example.workutils.menu.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 菜单组 - * 定义一组相关的菜单选项 - */ -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class MenuGroup { - - /** - * 菜单组名称 - */ - private String name; - - /** - * 菜单选项列表 - */ - private List items; - - /** - * 静态工厂方法:从字符串数组创建菜单组 - * - * @param name 菜单组名称 - * @param lines 菜单选项字符串数组,如 "1. 选项一", "0. 返回" - */ - public static MenuGroup of(String name, String[] lines) { - List items = Arrays.stream(lines) - .filter(line -> line != null && !line.trim().isEmpty()) - .map(line -> { - String[] parts = line.trim().split("\\.", 2); - Integer code = Integer.parseInt(parts[0].trim()); - String description = parts.length > 1 ? parts[1].trim() : ""; - return new MenuItem(code, description, null); - }) - .collect(Collectors.toList()); - return new MenuGroup(name, items); - } - - /** - * 获取菜单选项数量 - */ - public int size() { - return items != null ? items.size() : 0; - } - - /** - * 根据选项编号获取菜单项 - */ - public MenuItem getItem(Integer code) { - if (items == null || code == null) { - return null; - } - return items.stream() - .filter(item -> code.equals(item.getCode())) - .findFirst() - .orElse(null); - } -} diff --git a/src/main/java/com/example/workutils/menu/model/MenuItem.java b/src/main/java/com/example/workutils/menu/model/MenuItem.java deleted file mode 100644 index a791483..0000000 --- a/src/main/java/com/example/workutils/menu/model/MenuItem.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.example.workutils.menu.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 菜单项 - * 表示菜单中的一个选项 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class MenuItem { - - /** - * 菜单选项编号 - */ - private Integer code; - - /** - * 菜单选项描述 - */ - private String description; - - /** - * 菜单选项处理器类名 - */ - private String handlerClass; -} diff --git a/src/main/java/com/example/workutils/tool/AbstractTool.java b/src/main/java/com/example/workutils/tool/AbstractTool.java new file mode 100644 index 0000000..cd8ef92 --- /dev/null +++ b/src/main/java/com/example/workutils/tool/AbstractTool.java @@ -0,0 +1,97 @@ +package com.example.workutils.tool; + +import lombok.extern.slf4j.Slf4j; + +import java.util.Scanner; + +/** + * 工具基类 + * 提供共享的菜单循环模板方法,消除各Handler中的重复代码 + * 子类只需实现handleChoice()定义具体业务逻辑 + */ +@Slf4j +public abstract class AbstractTool implements Tool { + + /** + * 模板方法:标准菜单交互循环 + * displayMenu → readChoice → if 0 return → handleChoice → repeat + */ + @Override + public void execute(Scanner scanner) { + while (true) { + printMenuTitle(getName()); + displayMenu(getMenuOptions()); + + int choice = readChoice(scanner); + scanner.nextLine(); + + if (choice == 0) { + info("返回上级菜单"); + return; + } + + try { + handleChoice(choice, scanner); + } catch (Exception e) { + error(getName() + "执行失败", e); + printError(e.getMessage()); + } + } + } + + /** + * 处理子菜单选择,子类实现具体switch-case逻辑 + */ + protected abstract void handleChoice(int choice, Scanner scanner) throws Exception; + + // ============ 共享菜单工具方法 ============ + + protected void displayMenu(String[] options) { + System.out.println("请选择操作:"); + for (String option : options) { + System.out.println(option); + } + } + + protected int readChoice(Scanner scanner) { + try { + System.out.print("请输入选项编号: "); + return scanner.nextInt(); + } catch (Exception e) { + return -1; + } + } + + protected void printMenuTitle(String title) { + System.out.println(); + System.out.println("========== " + title + " =========="); + } + + protected void printSuccess(String operation) { + System.out.println(operation + "完成!"); + } + + protected void printError(String message) { + System.out.println("操作失败: " + message); + } + + protected void printInvalidOption() { + System.out.println("无效选项"); + } + + protected void info(String message) { + log.info(message); + } + + protected void info(String message, Object... args) { + log.info(message, args); + } + + protected void error(String message) { + log.error(message); + } + + protected void error(String message, Exception e) { + log.error(message, e); + } +} diff --git a/src/main/java/com/example/workutils/tool/Tool.java b/src/main/java/com/example/workutils/tool/Tool.java new file mode 100644 index 0000000..3875c94 --- /dev/null +++ b/src/main/java/com/example/workutils/tool/Tool.java @@ -0,0 +1,35 @@ +package com.example.workutils.tool; + +import java.util.Scanner; + +/** + * 工具策略接口 + * 所有可插拔工具实现此接口,Spring自动发现Tool Bean + */ +public interface Tool { + + /** + * 工具唯一标识(用于配置启用/禁用) + * 示例: "scan", "mybatis", "batch", "git-health", "mybatis-generator" + */ + String getId(); + + /** + * 菜单显示名称 + * 示例: "关键词扫描", "MyBatis导出" + */ + String getName(); + + /** + * 子菜单选项 + * 返回空数组表示无子菜单 + */ + String[] getMenuOptions(); + + /** + * 执行工具的交互会话 + * + * @param scanner 控制台输入 + */ + void execute(Scanner scanner); +} diff --git a/src/main/java/com/example/workutils/tool/ToolRegistry.java b/src/main/java/com/example/workutils/tool/ToolRegistry.java new file mode 100644 index 0000000..2f60fa7 --- /dev/null +++ b/src/main/java/com/example/workutils/tool/ToolRegistry.java @@ -0,0 +1,97 @@ +package com.example.workutils.tool; + +import com.example.workutils.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 final List allTools; + private final WorkUtilsProperties properties; + private List enabledTools; + private Map toolByIdMap; + + /** + * Spring自动注入所有Tool Bean + * 新增工具只需创建@Component类实现Tool接口,无需修改此类 + */ + public ToolRegistry(List tools, WorkUtilsProperties properties) { + this.allTools = tools; + this.properties = properties; + } + + @PostConstruct + public void init() { + Set enabledIds = resolveEnabledIds(); + this.enabledTools = new ArrayList<>(); + this.toolByIdMap = new LinkedHashMap<>(); + + for (Tool tool : allTools) { + try { + if (enabledIds == null || enabledIds.contains(tool.getId())) { + enabledTools.add(tool); + toolByIdMap.put(tool.getId(), 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 List getEnabledTools() { + return Collections.unmodifiableList(enabledTools); + } + + /** + * 按ID查找工具 + */ + public Optional getToolById(String id) { + return Optional.ofNullable(toolByIdMap.get(id)); + } + + /** + * 根据配置解析启用的工具ID集合 + * 优先级: enabled白名单 > disabled黑名单 > 全部启用 + * + * @return null表示全部启用,否则为启用的ID集合 + */ + private Set 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 allIds = allTools.stream() + .map(Tool::getId) + .collect(Collectors.toSet()); + allIds.removeAll(toolsConfig.getDisabled()); + return allIds; + } + + return null; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e7a77cb..ea5b702 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,6 +7,20 @@ workutils: config-directory: "src/main/resources/config" export-directory: "D:/workspace/workutils/export" project-paths-file: "代码仓库项目路径.txt" + # Tool enable/disable config + # Option 1: whitelist - only these tools are enabled + # tools: + # enabled: + # - scan + # - mybatis + # - batch + # - git-health + # - mybatis-generator + # Option 2: blacklist - exclude these tools + # tools: + # disabled: + # - mybatis-generator + # Default: all tools enabled logging: level: