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