①逆向工程插件支持多数据源
②打包体积缩小
This commit is contained in:
@@ -132,6 +132,18 @@ public class MyBatisGeneratorPlugin implements Plugin {
|
||||
public String generate(List<String> tables, String modelDir, String xmlDir, String mapperDir) throws Exception {
|
||||
return generatorService.generateByTableNames(tables, true, modelDir, xmlDir, mapperDir);
|
||||
}
|
||||
@Override
|
||||
public List<String> getDatasourceNames() {
|
||||
return generatorService.getDatasourceNames();
|
||||
}
|
||||
@Override
|
||||
public void switchDatasource(String name) {
|
||||
generatorService.switchDatasource(name);
|
||||
}
|
||||
@Override
|
||||
public String getCurrentDatasourceName() {
|
||||
return generatorService.getCurrentDatasourceName();
|
||||
}
|
||||
};
|
||||
|
||||
javafx.application.Platform.runLater(() -> {
|
||||
|
||||
+65
-6
@@ -53,6 +53,9 @@ public class MyBatisGeneratorWindow {
|
||||
private TextField mapperDirField;
|
||||
private TreeView<String> projectTree;
|
||||
private ToggleGroup fillTargetGroup;
|
||||
private ComboBox<String> datasourceCmb;
|
||||
private Label dbUrlLabel;
|
||||
private Label dbUserLabel;
|
||||
|
||||
/** 表项(含复选框) */
|
||||
public static class TableItem {
|
||||
@@ -79,6 +82,12 @@ public class MyBatisGeneratorWindow {
|
||||
String getDbUrl();
|
||||
String getDbUsername();
|
||||
String generate(List<String> tables, String modelDir, String xmlDir, String mapperDir) throws Exception;
|
||||
/** 可用的数据源名称列表 */
|
||||
List<String> getDatasourceNames();
|
||||
/** 切换数据源 */
|
||||
void switchDatasource(String name);
|
||||
/** 当前选中的数据源名称 */
|
||||
String getCurrentDatasourceName();
|
||||
}
|
||||
|
||||
public MyBatisGeneratorWindow(GeneratorCallback callback, FileOperationHelper fileOperationHelper,
|
||||
@@ -177,19 +186,69 @@ public class MyBatisGeneratorWindow {
|
||||
}
|
||||
|
||||
private HBox createDbInfoSection() {
|
||||
HBox box = new HBox(20);
|
||||
HBox box = new HBox(15);
|
||||
box.setPadding(new Insets(8, 12, 8, 12));
|
||||
box.setStyle("-fx-background-color: #e8f0fe; -fx-background-radius: 4;");
|
||||
box.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
Label urlLabel = new Label("数据库: " + callback.getDbUrl());
|
||||
urlLabel.setFont(Font.font("Consolas", fsBody()));
|
||||
Label userLabel = new Label("用户: " + callback.getDbUsername());
|
||||
userLabel.setFont(Font.font("Microsoft YaHei", fsBody()));
|
||||
Label dsLabel = new Label("数据源:");
|
||||
dsLabel.setFont(Font.font("Microsoft YaHei", fsBody()));
|
||||
|
||||
box.getChildren().addAll(urlLabel, userLabel);
|
||||
datasourceCmb = new ComboBox<>();
|
||||
datasourceCmb.setPrefWidth(160);
|
||||
datasourceCmb.setStyle("-fx-font-size: " + fsBody() + "px;");
|
||||
|
||||
// 加载数据源列表
|
||||
refreshDatasourceList();
|
||||
datasourceCmb.setOnAction(e -> {
|
||||
String selected = datasourceCmb.getValue();
|
||||
if (selected != null) {
|
||||
callback.switchDatasource("默认配置".equals(selected) ? null : selected);
|
||||
updateDbInfo();
|
||||
}
|
||||
});
|
||||
|
||||
dbUrlLabel = new Label();
|
||||
dbUrlLabel.setFont(Font.font("Consolas", fsBody() - 1));
|
||||
dbUserLabel = new Label();
|
||||
dbUserLabel.setFont(Font.font("Microsoft YaHei", fsBody() - 1));
|
||||
updateDbInfo();
|
||||
|
||||
Button refreshDsBtn = new Button("刷新");
|
||||
refreshDsBtn.setStyle("-fx-font-size: " + (fsBody() - 1) + "px; -fx-padding: 2 8;");
|
||||
refreshDsBtn.setOnAction(e -> {
|
||||
refreshDatasourceList();
|
||||
updateDbInfo();
|
||||
});
|
||||
|
||||
VBox infoBox = new VBox(3, dbUrlLabel, dbUserLabel);
|
||||
|
||||
box.getChildren().addAll(dsLabel, datasourceCmb, refreshDsBtn, infoBox);
|
||||
return box;
|
||||
}
|
||||
|
||||
private void refreshDatasourceList() {
|
||||
String current = datasourceCmb.getValue();
|
||||
datasourceCmb.getItems().clear();
|
||||
datasourceCmb.getItems().add("默认配置");
|
||||
datasourceCmb.getItems().addAll(callback.getDatasourceNames());
|
||||
if (current != null && datasourceCmb.getItems().contains(current)) {
|
||||
datasourceCmb.setValue(current);
|
||||
} else {
|
||||
String dsName = callback.getCurrentDatasourceName();
|
||||
if (dsName != null && datasourceCmb.getItems().contains(dsName)) {
|
||||
datasourceCmb.setValue(dsName);
|
||||
} else {
|
||||
datasourceCmb.setValue("默认配置");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDbInfo() {
|
||||
dbUrlLabel.setText("数据库: " + callback.getDbUrl());
|
||||
dbUserLabel.setText("用户: " + callback.getDbUsername());
|
||||
}
|
||||
|
||||
// ==================== 左侧:项目路径树 ====================
|
||||
|
||||
private VBox createProjectTreePanel() {
|
||||
|
||||
+97
-57
@@ -1,5 +1,7 @@
|
||||
package com.example.workutils.biz.mybatisgenerator.service.generator;
|
||||
|
||||
import com.example.workutils.system.config.DatasourceConfig;
|
||||
import com.example.workutils.system.config.DatasourceConfigManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.mybatis.generator.api.MyBatisGenerator;
|
||||
import org.mybatis.generator.config.Configuration;
|
||||
@@ -25,12 +27,40 @@ public class MyBatisGeneratorService {
|
||||
private static final String CONFIG_FILE = "mybatis-generator.xml";
|
||||
private static final String PROPERTIES_FILE = "mybatis-generator.properties";
|
||||
|
||||
private final DatasourceConfigManager datasourceMgr;
|
||||
/** 当前选中的数据源名称(null = 使用外部配置或内置默认配置) */
|
||||
private String currentDatasourceName;
|
||||
|
||||
public MyBatisGeneratorService(DatasourceConfigManager datasourceMgr) {
|
||||
this.datasourceMgr = datasourceMgr;
|
||||
}
|
||||
|
||||
// ==================== 数据源切换 ====================
|
||||
|
||||
public List<String> getDatasourceNames() {
|
||||
return datasourceMgr.getDatasourceNames();
|
||||
}
|
||||
|
||||
public DatasourceConfig getCurrentDatasource() {
|
||||
if (currentDatasourceName != null) {
|
||||
return datasourceMgr.findByName(currentDatasourceName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCurrentDatasourceName() {
|
||||
return currentDatasourceName;
|
||||
}
|
||||
|
||||
public void switchDatasource(String name) {
|
||||
this.currentDatasourceName = name;
|
||||
log.info("已切换数据源: {}", name != null ? name : "默认配置");
|
||||
}
|
||||
|
||||
// ==================== 生成入口 ====================
|
||||
|
||||
/**
|
||||
* 根据表名列表生成Mapper文件
|
||||
*
|
||||
* @param tableNames 表名列表
|
||||
* @param overwrite 是否覆盖已有文件
|
||||
* @return 生成结果信息
|
||||
*/
|
||||
public String generateByTableNames(List<String> tableNames, boolean overwrite) throws Exception {
|
||||
return generateInternal(tableNames, overwrite, null, null, null);
|
||||
@@ -46,40 +76,27 @@ public class MyBatisGeneratorService {
|
||||
|
||||
/**
|
||||
* 根据表名通配符生成Mapper文件
|
||||
* 先查询数据库中匹配的表,再进行逆向工程
|
||||
*
|
||||
* @param pattern 表名通配符(如 user_%)
|
||||
* @param overwrite 是否覆盖已有文件
|
||||
* @return 生成结果信息
|
||||
*/
|
||||
public String generateByPattern(String pattern, boolean overwrite) throws Exception {
|
||||
List<String> matchedTables = queryTablesByPattern(pattern);
|
||||
|
||||
if (matchedTables.isEmpty()) {
|
||||
return "未找到匹配通配符 [" + pattern + "] 的表";
|
||||
}
|
||||
|
||||
log.info("通配符 [{}] 匹配到 {} 张表: {}", pattern, matchedTables.size(), matchedTables);
|
||||
return generateInternal(matchedTables, overwrite, null, null, null);
|
||||
}
|
||||
|
||||
// ==================== 数据库查询 ====================
|
||||
|
||||
/**
|
||||
* 根据通配符查询数据库中的表
|
||||
*
|
||||
* @param pattern 表名通配符(支持 % 和 _ 通配符)
|
||||
* @return 匹配的表名列表
|
||||
*/
|
||||
public List<String> queryTablesByPattern(String pattern) throws Exception {
|
||||
List<String> tables = new ArrayList<>();
|
||||
Properties props = getConfigurationProperties();
|
||||
|
||||
String url = props.getProperty("db_url");
|
||||
String username = props.getProperty("db_username");
|
||||
String password = props.getProperty("db_password");
|
||||
|
||||
String dbName = extractDatabaseName(url);
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url, username, password)) {
|
||||
DbConnection db = getDbConnection();
|
||||
String dbName = extractDatabaseName(db.url);
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(db.url, db.username, db.password)) {
|
||||
String sql = "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME LIKE ?";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setString(1, dbName);
|
||||
@@ -91,26 +108,18 @@ public class MyBatisGeneratorService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据库中所有表
|
||||
*
|
||||
* @return 所有表名列表
|
||||
*/
|
||||
public List<String> queryAllTables() throws Exception {
|
||||
List<String> tables = new ArrayList<>();
|
||||
Properties props = getConfigurationProperties();
|
||||
|
||||
String url = props.getProperty("db_url");
|
||||
String username = props.getProperty("db_username");
|
||||
String password = props.getProperty("db_password");
|
||||
|
||||
String dbName = extractDatabaseName(url);
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url, username, password)) {
|
||||
DbConnection db = getDbConnection();
|
||||
String dbName = extractDatabaseName(db.url);
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(db.url, db.username, db.password)) {
|
||||
String sql = "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setString(1, dbName);
|
||||
@@ -121,10 +130,39 @@ public class MyBatisGeneratorService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前生效的数据库连接信息
|
||||
* 优先级: 选中的数据源 > 外部配置(workutils.config) > 内置classpath属性
|
||||
*/
|
||||
private DbConnection getDbConnection() {
|
||||
DatasourceConfig ds = getCurrentDatasource();
|
||||
if (ds != null) {
|
||||
return new DbConnection(ds.getUrl(), ds.getUsername(), ds.getPassword());
|
||||
}
|
||||
// 回退 classpath 配置
|
||||
Properties props = getClasspathProperties();
|
||||
return new DbConnection(
|
||||
props.getProperty("db_url", ""),
|
||||
props.getProperty("db_username", ""),
|
||||
props.getProperty("db_password", "")
|
||||
);
|
||||
}
|
||||
|
||||
/** 内部数据类:数据库连接信息 */
|
||||
private static class DbConnection {
|
||||
final String url;
|
||||
final String username;
|
||||
final String password;
|
||||
DbConnection(String url, String username, String password) {
|
||||
this.url = url;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JDBC URL中提取数据库名
|
||||
*/
|
||||
@@ -352,9 +390,22 @@ public class MyBatisGeneratorService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置属性
|
||||
* 获取配置属性(优先使用选中的数据源,回退到classpath)
|
||||
*/
|
||||
public Properties getConfigurationProperties() {
|
||||
Properties props = getClasspathProperties();
|
||||
// 如果选中了数据源,覆盖连接信息
|
||||
DatasourceConfig ds = getCurrentDatasource();
|
||||
if (ds != null) {
|
||||
if (ds.getDriver() != null) props.setProperty("db_driver", ds.getDriver());
|
||||
if (ds.getUrl() != null) props.setProperty("db_url", ds.getUrl());
|
||||
if (ds.getUsername() != null) props.setProperty("db_username", ds.getUsername());
|
||||
if (ds.getPassword() != null) props.setProperty("db_password", ds.getPassword());
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private Properties getClasspathProperties() {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE));
|
||||
@@ -364,38 +415,27 @@ public class MyBatisGeneratorService {
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库URL
|
||||
*/
|
||||
public String getDatabaseUrl() {
|
||||
return getConfigurationProperties().getProperty("db_url", "");
|
||||
DatasourceConfig ds = getCurrentDatasource();
|
||||
if (ds != null) return ds.getUrl();
|
||||
return getClasspathProperties().getProperty("db_url", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库用户名
|
||||
*/
|
||||
public String getDatabaseUsername() {
|
||||
return getConfigurationProperties().getProperty("db_username", "");
|
||||
DatasourceConfig ds = getCurrentDatasource();
|
||||
if (ds != null) return ds.getUsername();
|
||||
return getClasspathProperties().getProperty("db_username", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Model包路径
|
||||
*/
|
||||
public String getModelPackage() {
|
||||
return getConfigurationProperties().getProperty("model_package", "");
|
||||
return getClasspathProperties().getProperty("model_package", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Mapper包路径
|
||||
*/
|
||||
public String getMapperPackage() {
|
||||
return getConfigurationProperties().getProperty("dao_package", "");
|
||||
return getClasspathProperties().getProperty("dao_package", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SQL Mapper包路径
|
||||
*/
|
||||
public String getSqlMapperPackage() {
|
||||
return getConfigurationProperties().getProperty("sqlmapper_package", "");
|
||||
return getClasspathProperties().getProperty("sqlmapper_package", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.workutils.system.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 单条数据源配置
|
||||
*/
|
||||
@Data
|
||||
public class DatasourceConfig {
|
||||
|
||||
/** 显示名称(如"开发环境"、"SIT环境") */
|
||||
private String name;
|
||||
|
||||
/** JDBC 驱动类 */
|
||||
private String driver = "com.mysql.jdbc.Driver";
|
||||
|
||||
/** JDBC URL */
|
||||
private String url;
|
||||
|
||||
/** 用户名 */
|
||||
private String username;
|
||||
|
||||
/** 密码 */
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.example.workutils.system.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* 多数据源配置管理器
|
||||
* <p>
|
||||
* 从 data/datasources.json 加载数据源列表,供 MyBatis 逆向工程插件选择使用。
|
||||
* 首次运行时自动从 classpath 模板复制到 data/ 目录。
|
||||
*/
|
||||
@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 List<DatasourceConfig> datasources = new ArrayList<>();
|
||||
private Path configFile;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
configFile = Paths.get(System.getProperty("user.dir"), DATASOURCE_FILE);
|
||||
ensureConfigExists();
|
||||
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;
|
||||
try {
|
||||
String json = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8);
|
||||
List<DatasourceConfig> loaded = JSON.parseArray(json, DatasourceConfig.class);
|
||||
if (loaded != null) {
|
||||
datasources.addAll(loaded);
|
||||
}
|
||||
log.info("已加载 {} 套数据源配置", datasources.size());
|
||||
} catch (IOException e) {
|
||||
log.error("解析数据源配置失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取所有数据源名称列表 */
|
||||
public List<String> getDatasourceNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (DatasourceConfig ds : datasources) {
|
||||
names.add(ds.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/** 根据名称查找数据源配置 */
|
||||
public DatasourceConfig findByName(String name) {
|
||||
return datasources.stream()
|
||||
.filter(ds -> ds.getName().equals(name))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/** 获取配置文件的路径(供设置窗口打开编辑) */
|
||||
public Path getConfigFile() {
|
||||
return configFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"name": "开发环境",
|
||||
"driver": "com.mysql.jdbc.Driver",
|
||||
"url": "jdbc:mysql://localhost:3306/disburse?useUnicode=true&characterEncoding=utf8&useSSL=false",
|
||||
"username": "root",
|
||||
"password": "1Qaz@4772"
|
||||
},
|
||||
{
|
||||
"name": "SIT环境",
|
||||
"driver": "com.mysql.jdbc.Driver",
|
||||
"url": "jdbc:mysql://sit-server:3306/disburse?useUnicode=true&characterEncoding=utf8&useSSL=false",
|
||||
"username": "sit_user",
|
||||
"password": ""
|
||||
},
|
||||
{
|
||||
"name": "生产环境(只读)",
|
||||
"driver": "com.mysql.jdbc.Driver",
|
||||
"url": "jdbc:mysql://prod-server:3306/disburse?useUnicode=true&characterEncoding=utf8&useSSL=false",
|
||||
"username": "readonly",
|
||||
"password": ""
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user