优化通配符逆向工程
This commit is contained in:
+94
-28
@@ -9,11 +9,10 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.sql.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,58 +39,130 @@ public class MyBatisGeneratorService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据表名通配符生成Mapper文件
|
* 根据表名通配符生成Mapper文件
|
||||||
|
* 先查询数据库中匹配的表,再进行逆向工程
|
||||||
*
|
*
|
||||||
* @param pattern 表名通配符(如 user_%)
|
* @param pattern 表名通配符(如 user_%)
|
||||||
* @param overwrite 是否覆盖已有文件
|
* @param overwrite 是否覆盖已有文件
|
||||||
* @return 生成结果信息
|
* @return 生成结果信息
|
||||||
*/
|
*/
|
||||||
public String generateByPattern(String pattern, boolean overwrite) throws Exception {
|
public String generateByPattern(String pattern, boolean overwrite) throws Exception {
|
||||||
List<String> patterns = new ArrayList<>();
|
// 查询数据库中匹配通配符的表
|
||||||
patterns.add(pattern);
|
List<String> matchedTables = queryTablesByPattern(pattern);
|
||||||
return generateInternal(patterns, overwrite);
|
|
||||||
|
if (matchedTables.isEmpty()) {
|
||||||
|
return "未找到匹配通配符 [" + pattern + "] 的表";
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("通配符 [{}] 匹配到 {} 张表: {}", pattern, matchedTables.size(), matchedTables);
|
||||||
|
return generateInternal(matchedTables, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据通配符查询数据库中的表
|
||||||
|
*
|
||||||
|
* @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");
|
||||||
|
|
||||||
|
// 从URL中提取数据库名
|
||||||
|
String dbName = extractDatabaseName(url);
|
||||||
|
|
||||||
|
try (Connection conn = DriverManager.getConnection(url, username, 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);
|
||||||
|
ps.setString(2, pattern);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
tables.add(rs.getString("TABLE_NAME"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
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);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
tables.add(rs.getString("TABLE_NAME"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从JDBC URL中提取数据库名
|
||||||
|
*/
|
||||||
|
private String extractDatabaseName(String url) {
|
||||||
|
// jdbc:mysql://localhost:3306/disburse?xxx -> disburse
|
||||||
|
int start = url.lastIndexOf('/');
|
||||||
|
int end = url.indexOf('?', start);
|
||||||
|
if (end == -1) {
|
||||||
|
end = url.length();
|
||||||
|
}
|
||||||
|
return url.substring(start + 1, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内部生成方法
|
* 内部生成方法
|
||||||
*
|
|
||||||
* @param tableNames 表名列表
|
|
||||||
* @param overwrite 是否覆盖已有文件
|
|
||||||
* @return 生成结果信息
|
|
||||||
*/
|
*/
|
||||||
private String generateInternal(List<String> tableNames, boolean overwrite) throws Exception {
|
private String generateInternal(List<String> tableNames, boolean overwrite) throws Exception {
|
||||||
// 动态修改配置文件中的表配置
|
|
||||||
File tempConfigFile = createTempConfigWithTables(tableNames);
|
File tempConfigFile = createTempConfigWithTables(tableNames);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 解析临时配置文件
|
|
||||||
List<String> warnings = new ArrayList<>();
|
List<String> warnings = new ArrayList<>();
|
||||||
|
|
||||||
// 设置使用 JDK 内置 XML 解析器
|
|
||||||
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
|
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
|
||||||
System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
|
System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
|
||||||
|
|
||||||
ConfigurationParser parser = new ConfigurationParser(warnings);
|
ConfigurationParser parser = new ConfigurationParser(warnings);
|
||||||
Configuration configuration = parser.parseConfiguration(tempConfigFile);
|
Configuration configuration = parser.parseConfiguration(tempConfigFile);
|
||||||
|
|
||||||
// 执行生成
|
|
||||||
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
|
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
|
||||||
MyBatisGenerator generator = new MyBatisGenerator(configuration, callback, warnings);
|
MyBatisGenerator generator = new MyBatisGenerator(configuration, callback, warnings);
|
||||||
generator.generate(null, null, null, true);
|
generator.generate(null, null, null, true);
|
||||||
|
|
||||||
// 收集结果信息
|
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
|
result.append("成功生成 ").append(tableNames.size()).append(" 张表的Mapper文件\n");
|
||||||
if (!warnings.isEmpty()) {
|
if (!warnings.isEmpty()) {
|
||||||
result.append("生成完成,有以下警告:\n");
|
result.append("警告信息:\n");
|
||||||
for (String warning : warnings) {
|
for (String warning : warnings) {
|
||||||
result.append("- ").append(warning).append("\n");
|
result.append("- ").append(warning).append("\n");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
result.append("生成成功!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
} finally {
|
} finally {
|
||||||
// 删除临时文件
|
|
||||||
if (tempConfigFile.exists()) {
|
if (tempConfigFile.exists()) {
|
||||||
tempConfigFile.delete();
|
tempConfigFile.delete();
|
||||||
}
|
}
|
||||||
@@ -99,10 +170,9 @@ public class MyBatisGeneratorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建临时配置文件,包含指定的表配置
|
* 创建临时配置文件
|
||||||
*/
|
*/
|
||||||
private File createTempConfigWithTables(List<String> tableNames) throws Exception {
|
private File createTempConfigWithTables(List<String> tableNames) throws Exception {
|
||||||
// 读取原始配置文件内容
|
|
||||||
InputStream is = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE);
|
InputStream is = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE);
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
throw new RuntimeException("无法找到配置文件: " + CONFIG_FILE);
|
throw new RuntimeException("无法找到配置文件: " + CONFIG_FILE);
|
||||||
@@ -118,11 +188,10 @@ public class MyBatisGeneratorService {
|
|||||||
content = sb.toString();
|
content = sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用正则表达式移除原有的 table 元素
|
// 移除原有的 table 元素
|
||||||
// 匹配 <table ... /> 或 <table ...></table>
|
java.util.regex.Pattern tablePattern = java.util.regex.Pattern.compile(
|
||||||
Pattern tablePattern = Pattern.compile(
|
|
||||||
"<table[^>]*/>|<table[^>]*>.*?</table>",
|
"<table[^>]*/>|<table[^>]*>.*?</table>",
|
||||||
Pattern.DOTALL
|
java.util.regex.Pattern.DOTALL
|
||||||
);
|
);
|
||||||
content = tablePattern.matcher(content).replaceAll("");
|
content = tablePattern.matcher(content).replaceAll("");
|
||||||
|
|
||||||
@@ -140,10 +209,8 @@ public class MyBatisGeneratorService {
|
|||||||
.append(" selectByExampleQueryId=\"false\"/>\n\n");
|
.append(" selectByExampleQueryId=\"false\"/>\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 </context> 标签前插入新的 table 元素
|
|
||||||
content = content.replace("</context>", tableElements.toString() + " </context>");
|
content = content.replace("</context>", tableElements.toString() + " </context>");
|
||||||
|
|
||||||
// 写入临时文件
|
|
||||||
File tempFile = File.createTempFile("mybatis-generator-temp", ".xml");
|
File tempFile = File.createTempFile("mybatis-generator-temp", ".xml");
|
||||||
try (FileOutputStream fos = new FileOutputStream(tempFile)) {
|
try (FileOutputStream fos = new FileOutputStream(tempFile)) {
|
||||||
fos.write(content.getBytes(StandardCharsets.UTF_8));
|
fos.write(content.getBytes(StandardCharsets.UTF_8));
|
||||||
@@ -154,7 +221,6 @@ public class MyBatisGeneratorService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据表名生成实体类名
|
* 根据表名生成实体类名
|
||||||
* 例如:user_info -> UserInfoPO
|
|
||||||
*/
|
*/
|
||||||
private String generateDomainObjectName(String tableName) {
|
private String generateDomainObjectName(String tableName) {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler {
|
|||||||
"1. 根据表名生成(单表)",
|
"1. 根据表名生成(单表)",
|
||||||
"2. 根据表名生成(多表,逗号分隔)",
|
"2. 根据表名生成(多表,逗号分隔)",
|
||||||
"3. 根据表名通配符生成(如 user_%)",
|
"3. 根据表名通配符生成(如 user_%)",
|
||||||
"4. 查看当前配置信息",
|
"4. 查看数据库所有表",
|
||||||
|
"5. 查看当前配置信息",
|
||||||
"0. 返回上级菜单"
|
"0. 返回上级菜单"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +65,9 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler {
|
|||||||
generateByPattern(scanner);
|
generateByPattern(scanner);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
showAllTables();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
showConfiguration();
|
showConfiguration();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -131,12 +135,46 @@ public class MyBatisGeneratorHandler extends AbstractMenuHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info("开始根据通配符 [{}] 生成Mapper文件", pattern);
|
// 先查询匹配的表
|
||||||
String result = generatorService.generateByPattern(pattern, true);
|
List<String> 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)) {
|
||||||
|
System.out.println("已取消生成");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info("开始根据通配符 [{}] 生成 {} 张表的Mapper文件", pattern, matchedTables.size());
|
||||||
|
String result = generatorService.generateByTableNames(matchedTables, true);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
printSuccess("生成完成");
|
printSuccess("生成完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示数据库中所有表
|
||||||
|
*/
|
||||||
|
private void showAllTables() throws Exception {
|
||||||
|
List<String> tables = generatorService.queryAllTables();
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("========== 数据库所有表(共 " + tables.size() + " 张)==========");
|
||||||
|
for (int i = 0; i < tables.size(); i++) {
|
||||||
|
System.out.println(" " + (i + 1) + ". " + tables.get(i));
|
||||||
|
}
|
||||||
|
System.out.println("=================================");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示当前配置信息
|
* 显示当前配置信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user