From 0e95bf30a0bec749632371a988f0f476180b198b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=B6=E8=AE=AD?= Date: Wed, 17 Jun 2026 16:08:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=93=E5=BA=93=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../MyBatisGeneratorPlugin.java | 46 ++++++++----- .../MyBatisGeneratorWindow.java | 10 +++ .../generator/MyBatisGeneratorService.java | 66 +++++++++++++----- .../system/config/ConfigInitializer.java | 15 +++-- .../config/DatasourceConfigManager.java | 47 ++++--------- .../system/config/ExternalConfigManager.java | 50 +++----------- .../system/config/SettingsWindow.java | 17 ++++- .../system/config/WorkUtilsProperties.java | 63 ++++++++++++++--- src/main/resources/application.yml | 3 + .../templates/mybatis-generator.properties | 11 +++ .../resources/templates/project_paths.txt | 67 +++++++++++++++++++ src/main/resources/templates/workutils.config | 28 ++++++++ 13 files changed, 296 insertions(+), 129 deletions(-) create mode 100644 src/main/resources/templates/mybatis-generator.properties create mode 100644 src/main/resources/templates/workutils.config diff --git a/pom.xml b/pom.xml index 8c0315b..edbd34f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.example workutils - 0.0.2-SNAPSHOT + 1.0.1-SNAPSHOT workutils workutils diff --git a/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorPlugin.java b/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorPlugin.java index ddf7077..414a85d 100644 --- a/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorPlugin.java +++ b/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorPlugin.java @@ -11,6 +11,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Properties; import java.util.Scanner; @@ -62,27 +64,37 @@ public class MyBatisGeneratorPlugin implements Plugin { return "MyBatis 外部配置中数据库 URL 未设置。\n请通过「系统设置 > MyBatis 数据库」标签页补充。"; } - // 2. 回退检查内置 classpath 配置 + // 2. 回退检查 data/ 外部配置 → classpath 内置配置 + Properties props = new Properties(); + // 2a. 先尝试 classpath 内置值(作为基线) try (InputStream is = getClass().getClassLoader() .getResourceAsStream("mybatis-generator.properties")) { - if (is == null) { - return "MyBatis 生成器配置文件不存在: mybatis-generator.properties\n" - + "请在 src/main/resources/ 下创建此文件,完成后重新打包。\n" - + "或通过「系统设置 > MyBatis 数据库」标签页配置数据库连接。"; - } - Properties props = new Properties(); - props.load(is); - String dbUrl = props.getProperty("db_url", ""); - String dbUser = props.getProperty("db_username", ""); - if (dbUrl.isEmpty() || dbUser.isEmpty()) { - return "MyBatis 生成器数据库配置不完整:\n" - + " db_url = " + (dbUrl.isEmpty() ? "(未设置)" : dbUrl) + "\n" - + " db_username = " + (dbUser.isEmpty() ? "(未设置)" : dbUser) + "\n" - + "请编辑 src/main/resources/mybatis-generator.properties 后重新打包,\n" - + "或通过「系统设置 > MyBatis 数据库」标签页配置。"; + if (is != null) { + props.load(is); } } catch (Exception e) { - return "无法读取 MyBatis 生成器配置文件:\n错误: " + e.getMessage(); + log.warn("无法读取 classpath 内置配置", e); + } + // 2b. 用 data/ 外部配置覆盖 + Path dataFile = properties.getMybatisGeneratorFilePath(); + if (Files.exists(dataFile)) { + try (InputStream is = new java.io.FileInputStream(dataFile.toFile())) { + Properties externalProps = new Properties(); + externalProps.load(is); + props.putAll(externalProps); + } catch (Exception e) { + log.warn("无法读取 data/ MyBatis 配置", e); + } + } + + String dbUrl = props.getProperty("db_url", ""); + String dbUser = props.getProperty("db_username", ""); + if (dbUrl.isEmpty() || dbUser.isEmpty()) { + return "MyBatis 生成器数据库配置不完整:\n" + + " db_url = " + (dbUrl.isEmpty() ? "(未设置)" : dbUrl) + "\n" + + " db_username = " + (dbUser.isEmpty() ? "(未设置)" : dbUser) + "\n" + + "请在 data/mybatis-generator.properties 中编辑数据库连接信息,\n" + + "或通过「系统设置 > MyBatis 数据库」标签页配置。"; } return null; } diff --git a/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorWindow.java b/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorWindow.java index 13ea394..d6ed2ae 100644 --- a/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorWindow.java +++ b/src/main/java/com/example/workutils/biz/mybatisgenerator/MyBatisGeneratorWindow.java @@ -448,9 +448,19 @@ public class MyBatisGeneratorWindow { private void loadDefaultDirs() { Properties p = new Properties(); + // 1. classpath 内置默认值 try (InputStream is = getClass().getClassLoader().getResourceAsStream("mybatis-generator.properties")) { if (is != null) p.load(is); } catch (Exception ignored) {} + // 2. data/ 外部配置覆盖 + Path dataFile = properties.getMybatisGeneratorFilePath(); + if (java.nio.file.Files.exists(dataFile)) { + try (InputStream is = new java.io.FileInputStream(dataFile.toFile())) { + Properties externalProps = new Properties(); + externalProps.load(is); + p.putAll(externalProps); + } catch (Exception ignored) {} + } setDirField(modelDirField, p.getProperty("model_target_project", "./generator")); setDirField(xmlDirField, p.getProperty("sqlmapper_target_project", "./generator")); diff --git a/src/main/java/com/example/workutils/biz/mybatisgenerator/service/generator/MyBatisGeneratorService.java b/src/main/java/com/example/workutils/biz/mybatisgenerator/service/generator/MyBatisGeneratorService.java index fae1bcc..1d45635 100644 --- a/src/main/java/com/example/workutils/biz/mybatisgenerator/service/generator/MyBatisGeneratorService.java +++ b/src/main/java/com/example/workutils/biz/mybatisgenerator/service/generator/MyBatisGeneratorService.java @@ -2,6 +2,7 @@ package com.example.workutils.biz.mybatisgenerator.service.generator; import com.example.workutils.system.config.DatasourceConfig; import com.example.workutils.system.config.DatasourceConfigManager; +import com.example.workutils.system.config.WorkUtilsProperties; import lombok.extern.slf4j.Slf4j; import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.config.Configuration; @@ -11,6 +12,8 @@ import org.springframework.stereotype.Service; import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.sql.*; import java.util.ArrayList; import java.util.List; @@ -25,14 +28,16 @@ import java.util.Properties; public class MyBatisGeneratorService { private static final String CONFIG_FILE = "mybatis-generator.xml"; - private static final String PROPERTIES_FILE = "mybatis-generator.properties"; + private static final String CLASSPATH_PROPERTIES = "mybatis-generator.properties"; private final DatasourceConfigManager datasourceMgr; - /** 当前选中的数据源名称(null = 使用外部配置或内置默认配置) */ + private final WorkUtilsProperties workUtilsProperties; + /** 当前选中的数据源名称(null = 使用 data/ 外部配置或内置默认配置) */ private String currentDatasourceName; - public MyBatisGeneratorService(DatasourceConfigManager datasourceMgr) { + public MyBatisGeneratorService(DatasourceConfigManager datasourceMgr, WorkUtilsProperties workUtilsProperties) { this.datasourceMgr = datasourceMgr; + this.workUtilsProperties = workUtilsProperties; } // ==================== 数据源切换 ==================== @@ -142,8 +147,8 @@ public class MyBatisGeneratorService { if (ds != null) { return new DbConnection(ds.getUrl(), ds.getUsername(), ds.getPassword()); } - // 回退 classpath 配置 - Properties props = getClasspathProperties(); + // 回退: data/ 外部配置 → classpath 内置配置 + Properties props = loadMybatisProperties(); return new DbConnection( props.getProperty("db_url", ""), props.getProperty("db_username", ""), @@ -250,6 +255,15 @@ public class MyBatisGeneratorService { content = sb.toString(); } + // 将 classpath 资源引用替换为 data/ 外部文件的 file:// URL + Path propsFile = workUtilsProperties.getMybatisGeneratorFilePath(); + if (Files.exists(propsFile)) { + String fileUrl = propsFile.toUri().toString(); + content = content.replace( + "", + ""); + } + // 截掉 之后的内容(防止尾随垃圾导致 XML 解析失败) int endIdx = content.lastIndexOf(""); if (endIdx >= 0) { @@ -390,10 +404,10 @@ public class MyBatisGeneratorService { } /** - * 获取配置属性(优先使用选中的数据源,回退到classpath) + * 获取配置属性(优先: 选中数据源 > data/ 外部配置 > classpath 内置配置) */ public Properties getConfigurationProperties() { - Properties props = getClasspathProperties(); + Properties props = loadMybatisProperties(); // 如果选中了数据源,覆盖连接信息 DatasourceConfig ds = getCurrentDatasource(); if (ds != null) { @@ -405,12 +419,30 @@ public class MyBatisGeneratorService { return props; } - private Properties getClasspathProperties() { + /** + * 加载 MyBatis 属性:优先从 data/ 目录,回退 classpath + */ + private Properties loadMybatisProperties() { Properties props = new Properties(); - try { - props.load(getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)); - } catch (Exception e) { - log.warn("无法加载配置属性文件", e); + // 1. 先从 classpath 加载内置默认值 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(CLASSPATH_PROPERTIES)) { + if (is != null) { + props.load(is); + } + } catch (IOException e) { + log.warn("无法加载 classpath 内置属性文件", e); + } + // 2. 再用 data/ 目录的外部配置覆盖 + Path dataFile = workUtilsProperties.getMybatisGeneratorFilePath(); + if (Files.exists(dataFile)) { + try (InputStream is = new FileInputStream(dataFile.toFile())) { + Properties externalProps = new Properties(); + externalProps.load(is); + props.putAll(externalProps); // 外部配置覆盖内置值 + log.debug("已从 data/ 加载 MyBatis 属性: {}", dataFile.toAbsolutePath()); + } catch (IOException e) { + log.warn("无法加载 data/ MyBatis 属性文件: {}", e.getMessage()); + } } return props; } @@ -418,24 +450,24 @@ public class MyBatisGeneratorService { public String getDatabaseUrl() { DatasourceConfig ds = getCurrentDatasource(); if (ds != null) return ds.getUrl(); - return getClasspathProperties().getProperty("db_url", ""); + return loadMybatisProperties().getProperty("db_url", ""); } public String getDatabaseUsername() { DatasourceConfig ds = getCurrentDatasource(); if (ds != null) return ds.getUsername(); - return getClasspathProperties().getProperty("db_username", ""); + return loadMybatisProperties().getProperty("db_username", ""); } public String getModelPackage() { - return getClasspathProperties().getProperty("model_package", ""); + return loadMybatisProperties().getProperty("model_package", ""); } public String getMapperPackage() { - return getClasspathProperties().getProperty("dao_package", ""); + return loadMybatisProperties().getProperty("dao_package", ""); } public String getSqlMapperPackage() { - return getClasspathProperties().getProperty("sqlmapper_package", ""); + return loadMybatisProperties().getProperty("sqlmapper_package", ""); } } diff --git a/src/main/java/com/example/workutils/system/config/ConfigInitializer.java b/src/main/java/com/example/workutils/system/config/ConfigInitializer.java index 49ddf2e..6180e0c 100644 --- a/src/main/java/com/example/workutils/system/config/ConfigInitializer.java +++ b/src/main/java/com/example/workutils/system/config/ConfigInitializer.java @@ -7,9 +7,13 @@ import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** - * 配置初始化器 —— Spring 启动完成后检查并合并外部配置 + * 配置初始化器 —— Spring 启动完成后加载外部配置 *

- * 优先级: workutils.config > application.yml > 默认值 + * data/ 目录下的配置文件由 WorkUtilsProperties 在 @PostConstruct 阶段统一确保存在 + * (不存在时自动从 classpath:templates/ 复制)。 + * 本初始化器负责加载 workutils.config 并合并到运行属性中。 + *

+ * 优先级: data/workutils.config > application.yml > 默认值 */ @Slf4j @Component @@ -22,13 +26,10 @@ public class ConfigInitializer implements ApplicationListener * 从 data/datasources.json 加载数据源列表,供 MyBatis 逆向工程插件选择使用。 - * 首次运行时自动从 classpath 模板复制到 data/ 目录。 + * 配置文件的路径和首次复制由 WorkUtilsProperties 统一管理。 */ @Slf4j @Component public class DatasourceConfigManager { - private static final String DATASOURCE_FILE = "data/datasources.json"; - private static final String TEMPLATE_PATH = "templates/datasources.json"; - + private final WorkUtilsProperties properties; private final List datasources = new ArrayList<>(); - private Path configFile; + + public DatasourceConfigManager(WorkUtilsProperties properties) { + this.properties = properties; + } @PostConstruct void init() { - configFile = Paths.get(System.getProperty("user.dir"), DATASOURCE_FILE); - ensureConfigExists(); + // data/ 目录下的文件已由 WorkUtilsProperties 统一确保存在 reload(); } - /** 确保数据源配置文件存在 */ - private void ensureConfigExists() { - if (Files.exists(configFile)) return; - try { - Files.createDirectories(configFile.getParent()); - try (InputStream is = getClass().getClassLoader().getResourceAsStream(TEMPLATE_PATH)) { - if (is != null) { - Files.copy(is, configFile); - log.info("已从模板复制数据源配置: {}", configFile.toAbsolutePath()); - return; - } - } - } catch (IOException e) { - log.warn("复制数据源模板失败: {}", e.getMessage()); - } - // 兜底:创建空数组 - try { - Files.write(configFile, "[]".getBytes(StandardCharsets.UTF_8)); - log.info("已创建空数据源配置: {}", configFile.toAbsolutePath()); - } catch (IOException e) { - log.error("创建数据源配置文件失败", e); - } - } - /** 重新加载数据源配置 */ public synchronized void reload() { datasources.clear(); - if (!Files.exists(configFile)) return; + Path configFile = getConfigFile(); + if (!Files.exists(configFile)) { + log.warn("数据源配置文件不存在: {}", configFile.toAbsolutePath()); + return; + } try { String json = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8); List loaded = JSON.parseArray(json, DatasourceConfig.class); @@ -93,6 +72,6 @@ public class DatasourceConfigManager { /** 获取配置文件的路径(供设置窗口打开编辑) */ public Path getConfigFile() { - return configFile; + return properties.getDatasourcesFilePath(); } } diff --git a/src/main/java/com/example/workutils/system/config/ExternalConfigManager.java b/src/main/java/com/example/workutils/system/config/ExternalConfigManager.java index f198994..c1acfed 100644 --- a/src/main/java/com/example/workutils/system/config/ExternalConfigManager.java +++ b/src/main/java/com/example/workutils/system/config/ExternalConfigManager.java @@ -7,7 +7,6 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; @@ -15,9 +14,9 @@ import java.util.Properties; /** * 外部配置文件管理器 *

- * 管理 exe 同级目录下的 workutils.config 文件: + * 管理 data/ 目录下的 workutils.config 文件: *

    - *
  • 首次运行自动生成带注释的分段式默认配置
  • + *
  • 首次运行时由 WorkUtilsProperties 从 templates/ 复制到 data/
  • *
  • 运行时读写,优先级高于 application.yml
  • *
  • 支持热重载
  • *
  • 手动写入避免中文 Unicode 转义
  • @@ -27,7 +26,11 @@ import java.util.Properties; @Component public class ExternalConfigManager { - static final String CONFIG_FILE_NAME = "data/workutils.config"; + private final WorkUtilsProperties properties; + + public ExternalConfigManager(WorkUtilsProperties properties) { + this.properties = properties; + } // ---- 系统路径 ---- public static final String KEY_BASE_DIR = "base-directory"; @@ -78,9 +81,9 @@ public class ExternalConfigManager { }); } - /** 获取配置文件路径(exe 所在目录) */ + /** 获取配置文件路径 */ public Path getConfigFile() { - return Paths.get(System.getProperty("user.dir"), CONFIG_FILE_NAME); + return properties.getWorkutilsConfigFilePath(); } public boolean exists() { @@ -155,39 +158,4 @@ public class ExternalConfigManager { } } - /** - * 根据 application.yml 生成默认配置(数据文件、config文件均为 user.dir 同级目录) - */ - public Properties generateDefaults(WorkUtilsProperties appProps) { - Properties props = new Properties(); - props.setProperty(KEY_BASE_DIR, nvl(appProps.getBaseDirectory())); - props.setProperty(KEY_EXPORT_DIR, nvl(appProps.getExportDirectory())); - - // 数据文件用 user.dir 下的绝对路径 - props.setProperty(KEY_PROJECT_PATHS, appProps.getProjectPathsFilePath().toAbsolutePath().toString()); - props.setProperty(KEY_DAMAGED_REPOS, appProps.getDamagedReposFilePath().toAbsolutePath().toString()); - - // MyBatis 留空让用户填 - String[] mybatisKeys = { - KEY_MYBATIS_DRIVER, KEY_MYBATIS_URL, KEY_MYBATIS_USERNAME, - KEY_MYBATIS_PASSWORD, - KEY_MYBATIS_MODEL_PKG, KEY_MYBATIS_DAO_PKG, KEY_MYBATIS_SQLMAPPER_PKG - }; - for (String k : mybatisKeys) { - props.setProperty(k, ""); - } - - // 字体大小默认值 - props.setProperty(KEY_FONT_SECTION_TITLE, String.valueOf(appProps.getFontSectionTitle())); - props.setProperty(KEY_FONT_FIELD_LABEL, String.valueOf(appProps.getFontFieldLabel())); - props.setProperty(KEY_FONT_BUTTON, String.valueOf(appProps.getFontButton())); - props.setProperty(KEY_FONT_BODY, String.valueOf(appProps.getFontBody())); - props.setProperty(KEY_FONT_MONO, String.valueOf(appProps.getFontMono())); - - return props; - } - - private static String nvl(String s) { - return s == null ? "" : s; - } } diff --git a/src/main/java/com/example/workutils/system/config/SettingsWindow.java b/src/main/java/com/example/workutils/system/config/SettingsWindow.java index e3d1c36..8191427 100644 --- a/src/main/java/com/example/workutils/system/config/SettingsWindow.java +++ b/src/main/java/com/example/workutils/system/config/SettingsWindow.java @@ -16,6 +16,7 @@ import javafx.stage.Stage; import lombok.extern.slf4j.Slf4j; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -233,7 +234,7 @@ public class SettingsWindow { wrapper.getChildren().add(grid); - Button btnLoadBuiltin = new Button("从内置 mybatis-generator.properties 加载"); + Button btnLoadBuiltin = new Button("从 data/mybatis-generator.properties 加载"); btnLoadBuiltin.setFont(font(fontButton)); btnLoadBuiltin.setStyle("-fx-padding: 6 14;"); allButtons.add(btnLoadBuiltin); @@ -564,7 +565,8 @@ public class SettingsWindow { private void loadMyBatisFromClasspath() { Properties builtin = loadBuiltinMyBatisProps(); if (builtin.isEmpty()) { - showAlert(AlertType.WARNING, "未找到内置 mybatis-generator.properties 文件。"); + showAlert(AlertType.WARNING, "未找到 mybatis-generator.properties 配置文件。" + + "\n请检查 data/mybatis-generator.properties 是否存在。"); return; } tfDbDriver.setText(builtin.getProperty("db_driver", "")); @@ -579,6 +581,7 @@ public class SettingsWindow { private Properties loadBuiltinMyBatisProps() { Properties props = new Properties(); + // 1. 先从 classpath 加载内置默认值 try (InputStream is = getClass().getClassLoader() .getResourceAsStream("mybatis-generator.properties")) { if (is != null) { @@ -586,6 +589,16 @@ public class SettingsWindow { } } catch (IOException ignored) { } + // 2. 再用 data/ 外部配置覆盖 + Path dataFile = properties.getMybatisGeneratorFilePath(); + if (Files.exists(dataFile)) { + try (InputStream is = new FileInputStream(dataFile.toFile())) { + Properties externalProps = new Properties(); + externalProps.load(is); + props.putAll(externalProps); + } catch (IOException ignored) { + } + } return props; } diff --git a/src/main/java/com/example/workutils/system/config/WorkUtilsProperties.java b/src/main/java/com/example/workutils/system/config/WorkUtilsProperties.java index 1551bcf..7ec9123 100644 --- a/src/main/java/com/example/workutils/system/config/WorkUtilsProperties.java +++ b/src/main/java/com/example/workutils/system/config/WorkUtilsProperties.java @@ -50,6 +50,15 @@ public class WorkUtilsProperties { /** 损坏仓库缓存文件(相对路径时相对于 user.dir) */ private String damagedReposFile; + /** 数据源配置文件(相对路径时相对于 user.dir) */ + private String datasourcesFile; + + /** 外部配置文件(相对路径时相对于 user.dir) */ + private String workutilsConfigFile; + + /** MyBatis 生成器配置文件(相对路径时相对于 user.dir) */ + private String mybatisGeneratorFile; + /** 工具启用/禁用配置 */ private ToolsConfig tools; @@ -92,8 +101,8 @@ public class WorkUtilsProperties { defaults.put(ExternalConfigManager.KEY_EXPORT_DIR, exportDirectory); defaults.put(ExternalConfigManager.KEY_PROJECT_PATHS, projectPathsFile); defaults.put(ExternalConfigManager.KEY_DAMAGED_REPOS, damagedReposFile); - // 首次运行时确保数据文件存在于 user.dir 同级目录 - ensureDataFilesExist(); + // 首次运行时确保所有数据文件存在于 user.dir 同级 data/ 目录 + ensureAllDataFilesExist(); } /** 确保导出目录存在 */ @@ -202,7 +211,7 @@ public class WorkUtilsProperties { * 否则解析到 user.dir 下。 */ public Path getDamagedReposFilePath() { - Path p = Paths.get(damagedReposFile != null ? damagedReposFile : "damaged_repos.cache"); + Path p = Paths.get(damagedReposFile != null ? damagedReposFile : "data/damaged_repos.cache"); if (p.isAbsolute()) { return p; } @@ -210,16 +219,50 @@ public class WorkUtilsProperties { } /** - * 确保数据文件存在于 user.dir 同级目录。 - * 不存在时从 classpath:config/ 下复制模板内容(保留原始内容), - * 无法读取模板时则创建空文件。 + * 数据源配置文件的实际路径 */ - private void ensureDataFilesExist() { - ensureDataFile(getProjectPathsFilePath(), TEMPLATES_PATH + "project_paths.txt", "项目路径文件"); - ensureDataFile(getDamagedReposFilePath(), TEMPLATES_PATH + "damaged_repos.cache", "损坏缓存文件"); + public Path getDatasourcesFilePath() { + Path p = Paths.get(datasourcesFile != null ? datasourcesFile : "data/datasources.json"); + if (p.isAbsolute()) { + return p; + } + return Paths.get(System.getProperty("user.dir")).resolve(p); } - private static final String TEMPLATES_PATH = "templates/"; + /** + * 外部配置文件(workutils.config)的实际路径 + */ + public Path getWorkutilsConfigFilePath() { + Path p = Paths.get(workutilsConfigFile != null ? workutilsConfigFile : "data/workutils.config"); + if (p.isAbsolute()) { + return p; + } + return Paths.get(System.getProperty("user.dir")).resolve(p); + } + + /** + * MyBatis 生成器配置文件的实际路径 + */ + public Path getMybatisGeneratorFilePath() { + Path p = Paths.get(mybatisGeneratorFile != null ? mybatisGeneratorFile : "data/mybatis-generator.properties"); + if (p.isAbsolute()) { + return p; + } + return Paths.get(System.getProperty("user.dir")).resolve(p); + } + + /** + * 确保所有数据文件存在于 user.dir 同级 data/ 目录。 + * 启动时统一检查:不存在则从 classpath:templates/ 下复制模板。 + * 这是所有运行时数据文件的唯一入口。 + */ + private void ensureAllDataFilesExist() { + ensureDataFile(getWorkutilsConfigFilePath(), "templates/workutils.config", "外部配置文件"); + ensureDataFile(getDatasourcesFilePath(), "templates/datasources.json", "数据源配置"); + ensureDataFile(getProjectPathsFilePath(), "templates/project_paths.txt", "项目路径文件"); + ensureDataFile(getDamagedReposFilePath(), "templates/damaged_repos.cache", "损坏缓存文件"); + ensureDataFile(getMybatisGeneratorFilePath(), "templates/mybatis-generator.properties", "MyBatis生成器配置"); + } private void ensureDataFile(Path target, String classpathResource, String label) { try { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0e85812..d71896f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,6 +10,9 @@ workutils: # data file paths (relative -> under user.dir/data/, absolute -> as-is) project-paths-file: "data/project_paths.txt" damaged-repos-file: "data/damaged_repos.cache" + datasources-file: "data/datasources.json" + workutils-config-file: "data/workutils.config" + mybatis-generator-file: "data/mybatis-generator.properties" logging: charset: diff --git a/src/main/resources/templates/mybatis-generator.properties b/src/main/resources/templates/mybatis-generator.properties new file mode 100644 index 0000000..e0932a8 --- /dev/null +++ b/src/main/resources/templates/mybatis-generator.properties @@ -0,0 +1,11 @@ +db_driver=com.mysql.jdbc.Driver +db_url=jdbc:mysql://localhost:3306/disburse?useUnicode=true&characterEncoding=utf8&useSSL=false +db_username=root +db_password=1Qaz@4772 + +model_package=model +model_target_project=./generator +sqlmapper_package=mapperxml +sqlmapper_target_project=./generator +dao_package=mapper +dao_target_project=./generator diff --git a/src/main/resources/templates/project_paths.txt b/src/main/resources/templates/project_paths.txt index c073f66..affeea5 100644 --- a/src/main/resources/templates/project_paths.txt +++ b/src/main/resources/templates/project_paths.txt @@ -1,3 +1,70 @@ # 项目路径配置文件 # 格式: 本地路径=Git仓库URL(每行一个项目) # 示例: D:/workspace/my-project=https://user@code.example.com/org/repo.git +D:/bestpay-srdcloud/ft-compensatory-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-creative-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-credit-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-customer-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-file-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-finflux-gw-adapter=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-lending-management-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-loancapital-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-loan-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-organmng-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-orgsupport-weixin=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-protocol-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-repay-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-risk-control-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-settlement-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-wechatstage-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-agent-admin=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-batch-creditpayment=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-batch-creditpayment-plus=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-blockchain-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-boss=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-clrstl-fee-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-clrstl-report-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-codeutils=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-collateral-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-commodity-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-commonservice=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-consumestage-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-consumestage-mall=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credit-bizfront=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credit-bizfront-plus=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credit-front=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credit-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credit-prod-manage=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-creditstagescore=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-credituse-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-ctcorp-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-customer-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-file-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-govent-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-grant-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-info-collection=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-instalment-admin=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-instalment-batch=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-invoice-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-lending-management-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-loancapital-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-marketing-manage=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-marketing-manage-plus=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-onlinestage-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-organmng-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-precredit-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-productcfg-core-plus=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-protocol-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-risktool=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-scheduler=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-search=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-settlement-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-thirdpartybiz-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-trade-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/cf-wechatstage-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-approval-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-asset-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-blockchain-prod=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-collateral-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-commodity-core=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ +D:/bestpay-srdcloud/ft-commonservice=https://srd17321104074@code.srdcloud.cn/bestpay-cf/cf/ \ No newline at end of file diff --git a/src/main/resources/templates/workutils.config b/src/main/resources/templates/workutils.config new file mode 100644 index 0000000..c3313cb --- /dev/null +++ b/src/main/resources/templates/workutils.config @@ -0,0 +1,28 @@ +# ====== workutils 外部配置文件 ====== +# 编辑后通过「系统设置 > 重新加载」生效,无需重启 + +# ===== 系统路径 ===== +base-directory= +export-directory= + +# ===== 数据文件路径(相对于 user.dir)===== +project-paths-file=data/project_paths.txt +damaged-repos-file=data/damaged_repos.cache + +# ===== MyBatis 数据库连接(覆盖内置值)===== +mybatis.db.driver= +mybatis.db.url= +mybatis.db.username= +mybatis.db.password= + +# ===== MyBatis 代码生成包路径 ===== +mybatis.model.package= +mybatis.dao.package= +mybatis.sqlmapper.package= + +# ===== 字体大小(显示设置)===== +font.size.section-title=20 +font.size.field-label=18 +font.size.button=18 +font.size.body=18 +font.size.mono=18