可以连表生成文件,但是不正确

This commit is contained in:
2025-10-21 23:51:55 +08:00
parent cd421afc6c
commit 6e76d30bac
28 changed files with 2131 additions and 604 deletions

View File

@@ -0,0 +1,111 @@
---
trigger: always_on
alwaysApply: true
---
# 核心指令
作为自主项目开发AI你需要以CTO思维完整执行以下生命周期
1. 需求分析 → 2. 架构设计 → 3. 智能编码 → 4. 异常处理 → 5. 测试验证 → 6. 报告生成
# 执行规范
1. **思维记录机制**
-`/project_logs/` 下建立按时间戳命名的Markdown文件`YYYYMMDD_HHMMSS_phase.md`
- 每个决策节点记录:
```markdown
## [阶段] 项目里程碑
- 思考路径:[列出考虑的因素和决策树]
- 方案对比:
│─ 选项A
│ ├─ 优势
│ └─ 风险
└─ 选项B...
- 最终选择:附带可验证的决策依据
```
2. **自主开发协议**
- 采用「OODA循环」模式
```python
while not project_success:
observe(requirements)
orient(design_patterns)
decide(optimal_solution)
act(implement_and_test)
```
3. **异常处理矩阵**
- 建立 `/error_handling/` 知识库,分类处理:
│─ 逻辑错误 → 启用约束求解器
│─ 运行时异常 → 触发沙盒调试
└─ 系统依赖问题 → 自动环境检测
└─ 解决思考记录 → 后续异常参考
# 阶段详解
1. **需求拆解阶段**
- 输入:原始需求文档
- 输出:
- 功能点AST抽象语法树
- 非功能性需求矩阵(性能/安全/扩展性)
2. **架构设计阶段**
- 生成:
- 模块依赖图PlantUML格式
- 技术选型决策表(含权重评分)
3. **智能编码阶段**
- 实现:
- 自修正代码嵌入式TODO标注
- 自动生成单元测试桩
4. **测试套件**
- 实施三层验证:
1. 静态分析AST遍历检查
2. 动态模糊测试
3. 场景覆盖率检测
5. **报告生成**
- 输出三维度报告:
```latex
\section{质量指标}
- 代码熵值≤0.3
- 分支覆盖率≥85%
\section{待优化项}
- 内存泄露风险点定位
```
# 持久化要求
1. 版本化管理所有产物:
```
/project_artifacts/
├─ design/
│ └─ architecture_decision_record.md
├─ src/
│ └─ self_documenting_code.py
└─ tests/
├─ fuzz_test_cases.json
└─ coverage_visualization.html
```
2. 建立跨阶段索引文件:
```yaml
project_metadata:
timeline:
- phase: requirements_analysis
timestamp: ISO8601
decision_hash: SHA256
dependency_graph: neo4j_export.json
```
# 异常恢复协议
当检测到阻塞性问题时:
1. 自动生成最小可复现用例
2. 隔离到 `/quarantine/` 目录
3. 激活备选方案评估流程(蒙特卡洛模拟)
# 优化反馈循环
在每次迭代后:
- 用强化学习调整自身prompt权重
- 更新 `/knowledge_base/` 中的模式库
- 生成改进路线图(含时间预估)
请确认理解上述框架并以结构化JSON格式输出首个决策检查点。

View File

@@ -0,0 +1,24 @@
---
trigger: always_on
alwaysApply: true
---
严格遵循阿里巴巴Java开发规范包括但不限于
- 命名规范
- 代码格式
- 注释规范
- 异常处理规范
- 数据库操作规范
- 缓存操作规范
- 日志记录规范
- 性能优化规范
严格遵守JavaScript,Html,Css规范包括但不限于
- 命名规范
- 代码格式
- 注释规范
- 异常处理规范
- 数据库操作规范
- 缓存操作规范
- 日志记录规范
- 性能优化规范

4
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "interactive",
"java.compile.nullAnalysis.mode": "automatic"
}

View File

@@ -103,6 +103,25 @@
<artifactId>lombok</artifactId>
<version>1.18.40</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>example.Db2JavaExample</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -5,7 +5,11 @@ import com.yexuejc.db2java.core.enums.TemplateEngine;
import com.yexuejc.db2java.core.generator.*;
import com.yexuejc.db2java.core.template.TemplateEngineFactory;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import com.yexuejc.db2java.core.utils.DatabaseUtils;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;
/**
@@ -15,8 +19,38 @@ import java.util.List;
* @author yexuejc
* @since 2025-01
*/
@Slf4j
public class Db2JavaCore {
/**
* 根据配置生成代码的主方法
*
* @param config 生成配置
* @return 生成结果
* @throws Exception 生成异常
*/
public static GenerationResult generate(GenerationConfig config) throws Exception {
// 建立数据库连接
Connection connection = DriverManager.getConnection(
config.getUrl(),
config.getUsername(),
config.getPassword()
);
try {
// 获取表信息
List<TableInfo> tableInfos = DatabaseUtils.getTableInfos(connection, config);
System.out.println("获取表信息成功,共有" + tableInfos.size() + "张表");
System.out.println("开始调用引擎生成代码");
// 调用原有的generateCode方法
return generateCode(tableInfos, config);
} finally {
if (connection != null && !connection.isClosed()) {
connection.close();
}
}
}
/**
* 生成代码的主方法
*
@@ -27,21 +61,27 @@ public class Db2JavaCore {
*/
public static GenerationResult generateCode(List<TableInfo> tableInfos, GenerationConfig config) throws Exception {
// 验证配置
System.out.println("验证生成配置");
validateConfig(config);
// 获取代码生成器
System.out.println("获取代码生成器");
CodeGenerator codeGenerator = CodeGeneratorFactory.getGenerator(config.getMode());
// 获取模板引擎处理器
System.out.println("获取模板引擎处理器");
TemplateEngineProcessor templateProcessor = TemplateEngineFactory.getProcessor(config.getEngine());
// 初始化生成器
System.out.println("初始化代码生成器");
codeGenerator.initialize(config);
// 初始化模板引擎
System.out.println("初始化模板引擎处理器");
templateProcessor.initialize(null);
// 执行代码生成
System.out.println("开始执行代码生成");
return codeGenerator.generate(tableInfos, config);
}

View File

@@ -53,6 +53,31 @@ public class FieldInfo {
*/
private Integer scale;
/**
* 数据类型代码
*/
private int dataType;
/**
* 默认值
*/
private String defaultValue;
/**
* 字段在表中的位置
*/
private int ordinalPosition;
/**
* 小数位数
*/
private int decimalDigits;
/**
* 字段大小
*/
private int columnSize;
public FieldInfo() {
}
@@ -135,4 +160,44 @@ public class FieldInfo {
public void setScale(Integer scale) {
this.scale = scale;
}
public int getDataType() {
return dataType;
}
public void setDataType(int dataType) {
this.dataType = dataType;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public int getOrdinalPosition() {
return ordinalPosition;
}
public void setOrdinalPosition(int ordinalPosition) {
this.ordinalPosition = ordinalPosition;
}
public int getDecimalDigits() {
return decimalDigits;
}
public void setDecimalDigits(int decimalDigits) {
this.decimalDigits = decimalDigits;
}
public int getColumnSize() {
return columnSize;
}
public void setColumnSize(int columnSize) {
this.columnSize = columnSize;
}
}

View File

@@ -10,6 +10,26 @@ import java.util.Map;
*/
public class GenerationConfig {
/**
* 数据库URL
*/
private String url;
/**
* 数据库用户名
*/
private String username;
/**
* 数据库密码
*/
private String password;
/**
* 数据库驱动类名
*/
private String driverClassName;
/**
* 生成模式
*/
@@ -79,6 +99,38 @@ public class GenerationConfig {
}
// Getter and Setter methods
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getMode() {
return mode;
}
@@ -111,6 +163,11 @@ public class GenerationConfig {
this.outputPath = outputPath;
}
// 兼容旧版本的setter方法
public void setOutDir(String outDir) {
this.outputPath = outDir;
}
public String getPackageName() {
return packageName;
}

View File

@@ -5,6 +5,7 @@ import com.yexuejc.db2java.core.generator.*;
import com.yexuejc.db2java.core.template.TemplateEngineFactory;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import com.yexuejc.db2java.core.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -15,6 +16,7 @@ import java.util.*;
* @author yexuejc
* @since 2025-01
*/
@Slf4j
public class HibernateCodeGenerator implements CodeGenerator {
@Override
@@ -81,6 +83,7 @@ public class HibernateCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Entity", content);
} catch (Exception e) {
System.err.println("生成Hibernate Entity失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -315,6 +318,7 @@ public class HibernateCodeGenerator implements CodeGenerator {
generatedFile.setFileSize(FileUtils.getFileSize(generatedFile.getFilePath()));
} catch (Exception e) {
System.err.println("写入文件失败: " + generatedFile.getFilePath() + ", 错误: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -5,6 +5,7 @@ import com.yexuejc.db2java.core.generator.*;
import com.yexuejc.db2java.core.template.TemplateEngineFactory;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import com.yexuejc.db2java.core.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -15,6 +16,7 @@ import java.util.*;
* @author yexuejc
* @since 2025-01
*/
@Slf4j
public class JpaCodeGenerator implements CodeGenerator {
@Override
@@ -81,6 +83,7 @@ public class JpaCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Entity", content);
} catch (Exception e) {
System.err.println("生成JPA Entity失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -387,6 +390,7 @@ public class JpaCodeGenerator implements CodeGenerator {
generatedFile.setFileSize(FileUtils.getFileSize(generatedFile.getFilePath()));
} catch (Exception e) {
System.err.println("写入文件失败: " + generatedFile.getFilePath() + ", 错误: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -5,6 +5,7 @@ import com.yexuejc.db2java.core.generator.*;
import com.yexuejc.db2java.core.template.TemplateEngineFactory;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import com.yexuejc.db2java.core.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -15,6 +16,7 @@ import java.util.*;
* @author yexuejc
* @since 2025-01
*/
@Slf4j
public class MybatisCodeGenerator implements CodeGenerator {
@Override
@@ -189,9 +191,12 @@ public class MybatisCodeGenerator implements CodeGenerator {
dataModel.put("entity", tableInfo.getEntityName());
dataModel.put("table", createTableMap(tableInfo));
// 导入包
dataModel.put("importEntityFrameworkPackages", getEntityImports(config.isLombok()));
dataModel.put("importEntityJavaPackages", getJavaImports(tableInfo));
// 导入包 - 确保顺序一致
List<String> entityFrameworkImports = getEntityFrameworkImports(config.isLombok());
List<String> entityJavaImports = getEntityJavaImports(tableInfo);
dataModel.put("importEntityFrameworkPackages", entityFrameworkImports);
dataModel.put("importEntityJavaPackages", entityJavaImports);
// Lombok配置
dataModel.put("entityLombokModel", config.isLombok());
@@ -403,16 +408,19 @@ public class MybatisCodeGenerator implements CodeGenerator {
}
/**
* 获取实体类框架导入包
* 获取实体类框架导入包 - 确保顺序一致
*/
private List<String> getEntityImports(boolean useLombok) {
private List<String> getEntityFrameworkImports(boolean useLombok) {
List<String> imports = new ArrayList<>();
// 添加Lombok导入
// 添加Lombok导入(如果使用)
if (useLombok) {
imports.add("lombok.Data");
}
// 添加序列化导入
imports.add("java.io.Serializable");
// 添加关联字段需要的导入
imports.add("java.util.List");
@@ -420,27 +428,25 @@ public class MybatisCodeGenerator implements CodeGenerator {
}
/**
* 获取Java导入包
* 获取Java导入包 - 确保顺序一致
*/
private List<String> getJavaImports(TableInfo tableInfo) {
Set<String> imports = new HashSet<>();
imports.add("java.io.Serializable");
private List<String> getEntityJavaImports(TableInfo tableInfo) {
// 使用LinkedHashSet保持顺序并去重
Set<String> importSet = new LinkedHashSet<>();
// 根据字段类型添加相应的导入
for (FieldInfo field : tableInfo.getFields()) {
if ("LocalDateTime".equals(field.getPropertyType())) {
imports.add("java.time.LocalDateTime");
importSet.add("java.time.LocalDateTime");
} else if ("LocalDate".equals(field.getPropertyType())) {
imports.add("java.time.LocalDate");
importSet.add("java.time.LocalDate");
} else if ("BigDecimal".equals(field.getPropertyType())) {
imports.add("java.math.BigDecimal");
importSet.add("java.math.BigDecimal");
}
}
// 添加关联字段需要的导入
imports.add("java.util.List");
return new ArrayList<>(imports);
// 转换为列表并返回
return new ArrayList<>(importSet);
}
/**

View File

@@ -5,6 +5,7 @@ import com.yexuejc.db2java.core.generator.*;
import com.yexuejc.db2java.core.template.TemplateEngineFactory;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import com.yexuejc.db2java.core.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -15,6 +16,7 @@ import java.util.*;
* @author yexuejc
* @since 2025-01
*/
@Slf4j
public class MybatisPlusCodeGenerator implements CodeGenerator {
@Override
@@ -117,6 +119,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Entity", content);
} catch (Exception e) {
System.err.println("生成Entity失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -135,6 +138,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Mapper", content);
} catch (Exception e) {
System.err.println("生成Mapper失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -153,6 +157,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Service", content);
} catch (Exception e) {
System.err.println("生成Service失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -171,6 +176,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "ServiceImpl", content);
} catch (Exception e) {
System.err.println("生成ServiceImpl失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -189,6 +195,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
return new GeneratedFile(filePath, fileName, "Controller", content);
} catch (Exception e) {
System.err.println("生成Controller失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
@@ -407,8 +414,8 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
dataModel.put("superServiceImplClass", "com.baomidou.mybatisplus.extension.service.impl.ServiceImpl");
dataModel.put("superServiceImplClassPackage", "com.baomidou.mybatisplus.extension.service.impl.ServiceImpl");
dataModel.put("importServiceImplFrameworkPackages", Arrays.asList(
"com.baomidou.mybatisplus.extension.service.impl.ServiceImpl",
"org.springframework.stereotype.Service"
"com.baomidou.mybatisplus.extension.service.impl.ServiceImpl",
"org.springframework.stereotype.Service"
));
dataModel.put("importServiceImplJavaPackages", new ArrayList<>());
dataModel.put("kotlin", false);
@@ -446,9 +453,9 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
dataModel.put("superControllerClass", null); // 不继承任何类
dataModel.put("superControllerClassPackage", null);
dataModel.put("importControllerFrameworkPackages", Arrays.asList(
"org.springframework.web.bind.annotation.RestController",
"org.springframework.web.bind.annotation.RequestMapping",
"org.springframework.beans.factory.annotation.Autowired"
"org.springframework.web.bind.annotation.RestController",
"org.springframework.web.bind.annotation.RequestMapping",
"org.springframework.beans.factory.annotation.Autowired"
));
dataModel.put("importControllerJavaPackages", new ArrayList<>());
dataModel.put("restControllerStyle", true);
@@ -594,6 +601,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator {
generatedFile.setFileSize(FileUtils.getFileSize(generatedFile.getFilePath()));
} catch (Exception e) {
System.err.println("写入文件失败: " + generatedFile.getFilePath() + ", 错误: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -1,25 +1,29 @@
package com.yexuejc.db2java.core.template.impl;
import com.yexuejc.db2java.core.template.TemplateEngineProcessor;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.InputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
/**
* 改进的FreeMarker模板引擎处理器
* 提供更完整的模板处理能力
* Freemarker模板引擎处理器
*
* @author yexuejc
* @since 2025-01
*/
public class FreemarkerTemplateProcessor implements TemplateEngineProcessor {
public class FreemarkerTemplateProcessor implements TemplateEngineProcessor {
private Configuration configuration;
@Override
public String getEngineName() {
return "freemarker";
return "Freemarker";
}
@Override
@@ -29,89 +33,102 @@ import java.util.Scanner;
@Override
public void initialize(Map<String, Object> config) throws Exception {
System.out.println("改进的FreeMarker引擎初始化 - 配置: " + config);
configuration = new Configuration(Configuration.VERSION_2_3_32);
configuration.setDefaultEncoding("UTF-8");
configuration.setClassicCompatible(true);
configuration.setWhitespaceStripping(false);
// 设置模板加载路径
try {
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
} catch (Exception e) {
System.err.println("设置模板加载路径失败: " + e.getMessage());
}
}
@Override
public String processTemplate(String templatePath, Map<String, Object> dataModel) throws Exception {
// 调试输出
System.out.println("模板路径: " + templatePath);
// 直接根据模板路径判断生成类型,避免模板内容解析错误
return generateFallbackContent(templatePath, dataModel);
public String processTemplate(String templateName, Map<String, Object> dataModel) throws IOException, TemplateException {
// 确保configuration已初始化
if (configuration == null) {
try {
initialize(null);
} catch (Exception e) {
System.err.println("初始化Freemarker配置失败: " + e.getMessage());
// 使用硬编码处理逻辑
return generateCodeFromDataModel(templateName, dataModel);
}
}
// 尝试使用模板文件处理
try {
Template template = configuration.getTemplate(templateName);
StringWriter writer = new StringWriter();
template.process(dataModel, writer);
return writer.toString();
} catch (IOException e) {
// 如果模板文件不存在,使用硬编码处理逻辑
return generateCodeFromDataModel(templateName, dataModel);
}
}
@Override
public boolean templateExists(String templatePath) {
return readTemplateFile(templatePath) != null;
}
// 确保configuration已初始化
if (configuration == null) {
try {
initialize(null);
} catch (Exception e) {
System.err.println("初始化Freemarker配置失败: " + e.getMessage());
return false;
}
}
/**
* 读取模板文件
*/
private String readTemplateFile(String templatePath) {
try {
String fullPath = "/templates/" + templatePath;
InputStream inputStream = this.getClass().getResourceAsStream(fullPath);
if (inputStream == null) {
System.err.println("模板文件不存在: " + fullPath);
return null;
}
Scanner scanner = new Scanner(inputStream, "UTF-8");
StringBuilder content = new StringBuilder();
while (scanner.hasNextLine()) {
content.append(scanner.nextLine()).append("\n");
}
scanner.close();
inputStream.close();
return content.toString();
configuration.getTemplate(templatePath);
return true;
} catch (Exception e) {
System.err.println("读取模板文件失败: " + templatePath + ", 错误: " + e.getMessage());
return null;
return false;
}
}
/**
* 高级模板处理 - 根据模板类型生成相应的Java代码
* 从数据模型生成代码(硬编码处理逻辑)
*
* @param templateName 模板名称
* @param dataModel 数据模型
* @return 生成的代码
*/
private String processAdvancedTemplate(String template, Map<String, Object> dataModel) {
// 根据模板内容判断生成类型
if (template.contains("@RestController") || template.contains("@Controller")) {
return generateControllerCode(dataModel);
} else if (template.contains("interface") && template.contains("Service")) {
return generateServiceCode(dataModel);
} else if (template.contains("class") && template.contains("ServiceImpl")) {
return generateServiceImplCode(dataModel);
} else if (template.contains("interface") && template.contains("Mapper")) {
return generateMapperCode(dataModel);
} else if (template.contains("<?xml") || template.contains("<mapper")) {
private String generateCodeFromDataModel(String templateName, Map<String, Object> dataModel) {
if (templateName.startsWith("entity")) {
return generateEntityCode(dataModel);
} else if (templateName.startsWith("mapper.java")) {
return generateMapperJavaCode(dataModel);
} else if (templateName.startsWith("mapper.xml")) {
return generateMapperXmlCode(dataModel);
} else {
// 默认生成Entity代码
return generateEntityCode(dataModel);
// 默认处理逻辑
return generateDefaultCode(dataModel);
}
}
/**
* 生成Entity代码
* 生成实体类代码
*/
private String generateEntityCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
// 获取数据
@SuppressWarnings("unchecked")
Map<String, String> packageMap = (Map<String, String>) dataModel.get("package");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
String entity = safeString(dataModel.get("entity"));
String author = safeString(dataModel.get("author"));
String date = safeString(dataModel.get("date"));
Boolean lombok = (Boolean) dataModel.get("entityLombokModel");
Boolean serialVersionUID = (Boolean) dataModel.get("entitySerialVersionUID");
Boolean entityToString = (Boolean) dataModel.get("entityToString");
Boolean entityJpaModel = (Boolean) dataModel.get("entityJpaModel");
Boolean entityToString = (Boolean) dataModel.get("entityToString");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
// 包声明
if (packageMap != null && packageMap.get("Entity") != null) {
@@ -119,21 +136,27 @@ import java.util.Scanner;
}
// 导入语句
code.append("import java.io.Serializable;\n");
code.append("import java.time.LocalDateTime;\n");
code.append("import java.time.LocalDate;\n");
code.append("import java.math.BigDecimal;\n");
code.append("import java.util.List;\n");
@SuppressWarnings("unchecked")
List<String> importEntityFrameworkPackages = (List<String>) dataModel.get("importEntityFrameworkPackages");
@SuppressWarnings("unchecked")
List<String> importEntityJavaPackages = (List<String>) dataModel.get("importEntityJavaPackages");
// JPA导入
if (entityJpaModel != null && entityJpaModel) {
code.append("import javax.persistence.*;\n");
if (importEntityFrameworkPackages != null) {
for (String pkg : importEntityFrameworkPackages) {
code.append("import ").append(pkg).append(";\n");
}
}
if (lombok != null && lombok) {
code.append("import lombok.Data;\n");
if (importEntityJavaPackages != null) {
for (String pkg : importEntityJavaPackages) {
code.append("import ").append(pkg).append(";\n");
}
}
if ((importEntityFrameworkPackages != null && !importEntityFrameworkPackages.isEmpty()) ||
(importEntityJavaPackages != null && !importEntityJavaPackages.isEmpty())) {
code.append("\n");
}
code.append("\n");
// 类注释
code.append("/**\n");
@@ -147,19 +170,17 @@ import java.util.Scanner;
code.append(" * @since ").append(date).append("\n");
code.append(" */\n");
// JPA注解
if (entityJpaModel != null && entityJpaModel) {
code.append("@Entity\n");
code.append("@Table(name = \"").append(tableMap.get("name")).append("\")\n");
// 注解
@SuppressWarnings("unchecked")
List<Map<String, String>> entityClassAnnotations = (List<Map<String, String>>) dataModel.get("entityClassAnnotations");
if (entityClassAnnotations != null) {
for (Map<String, String> annotation : entityClassAnnotations) {
code.append(annotation.get("displayName")).append("\n");
}
}
// Lombok注解
if (lombok != null && lombok) {
code.append("@Data\n");
}
// 类声明
code.append("public class ").append(entity);
// 类声明 - 使用正确的实体类名
code.append("public class ").append(entity); // 这里使用entity变量与文件名一致
if (serialVersionUID != null && serialVersionUID) {
code.append(" implements Serializable");
}
@@ -366,186 +387,21 @@ import java.util.Scanner;
return code.toString();
}
/**
* 备用内容生成
*/
private String generateFallbackContent(String templatePath, Map<String, Object> dataModel) {
// 根据模板路径判断类型
if (templatePath.contains("controller")) {
return generateControllerCode(dataModel);
} else if (templatePath.contains("service") && !templatePath.contains("serviceImpl")) {
return generateServiceCode(dataModel);
} else if (templatePath.contains("serviceImpl")) {
return generateServiceImplCode(dataModel);
} else if (templatePath.contains("mapper") && (templatePath.contains(".xml") || templatePath.endsWith("xml.ftl"))) {
return generateMapperXmlCode(dataModel);
} else if (templatePath.contains("mapper")) {
return generateMapperCode(dataModel);
} else {
return generateEntityCode(dataModel);
}
}
/**
* 生成Controller代码
*/
private String generateControllerCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
@SuppressWarnings("unchecked")
Map<String, String> packageMap = (Map<String, String>) dataModel.get("package");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
String entity = safeString(dataModel.get("entity"));
String author = safeString(dataModel.get("author"));
String date = safeString(dataModel.get("date"));
// 包声明
if (packageMap != null && packageMap.get("Controller") != null) {
code.append("package ").append(packageMap.get("Controller")).append(";\n\n");
}
// 导入语句
code.append("import org.springframework.web.bind.annotation.RequestMapping;\n");
code.append("import org.springframework.web.bind.annotation.RestController;\n");
code.append("import org.springframework.beans.factory.annotation.Autowired;\n");
if (packageMap != null) {
code.append("import ").append(packageMap.get("Service")).append(".I").append(entity).append("Service;\n");
}
code.append("\n");
// 类注释
code.append("/**\n");
code.append(" * <p>\n");
if (tableMap != null && tableMap.get("comment") != null) {
code.append(" * ").append(tableMap.get("comment")).append(" 前端控制器\n");
}
code.append(" * </p>\n");
code.append(" *\n");
code.append(" * @author ").append(author).append("\n");
code.append(" * @since ").append(date).append("\n");
code.append(" */\n");
// 注解和类声明
code.append("@RestController\n");
code.append("@RequestMapping(\"/").append(entity.toLowerCase()).append("\")\n");
code.append("public class ").append(entity).append("Controller {\n\n");
// 注入Service
code.append(" @Autowired\n");
code.append(" private I").append(entity).append("Service ").append(entity.toLowerCase()).append("Service;\n\n");
code.append("}\n");
return code.toString();
}
/**
* 生成Service接口代码
*/
private String generateServiceCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
@SuppressWarnings("unchecked")
Map<String, String> packageMap = (Map<String, String>) dataModel.get("package");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
String entity = safeString(dataModel.get("entity"));
String author = safeString(dataModel.get("author"));
String date = safeString(dataModel.get("date"));
// 包声明
if (packageMap != null && packageMap.get("Service") != null) {
code.append("package ").append(packageMap.get("Service")).append(";\n\n");
}
// 导入语句
if (packageMap != null && packageMap.get("Entity") != null) {
code.append("import ").append(packageMap.get("Entity")).append(".").append(entity).append(";\n");
}
code.append("import com.baomidou.mybatisplus.extension.service.IService;\n\n");
// 类注释
code.append("/**\n");
code.append(" * <p>\n");
if (tableMap != null && tableMap.get("comment") != null) {
code.append(" * ").append(tableMap.get("comment")).append(" 服务类\n");
}
code.append(" * </p>\n");
code.append(" *\n");
code.append(" * @author ").append(author).append("\n");
code.append(" * @since ").append(date).append("\n");
code.append(" */\n");
// 接口声明
code.append("public interface I").append(entity).append("Service extends IService<").append(entity).append("> {\n\n");
code.append("}\n");
return code.toString();
}
/**
* 生成ServiceImpl代码
*/
private String generateServiceImplCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
@SuppressWarnings("unchecked")
Map<String, String> packageMap = (Map<String, String>) dataModel.get("package");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
String entity = safeString(dataModel.get("entity"));
String author = safeString(dataModel.get("author"));
String date = safeString(dataModel.get("date"));
// 包声明
if (packageMap != null && packageMap.get("ServiceImpl") != null) {
code.append("package ").append(packageMap.get("ServiceImpl")).append(";\n\n");
}
// 导入语句
if (packageMap != null) {
code.append("import ").append(packageMap.get("Entity")).append(".").append(entity).append(";\n");
code.append("import ").append(packageMap.get("Mapper")).append(".").append(entity).append("Mapper;\n");
code.append("import ").append(packageMap.get("Service")).append(".I").append(entity).append("Service;\n");
}
code.append("import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n");
code.append("import org.springframework.stereotype.Service;\n\n");
// 类注释
code.append("/**\n");
code.append(" * <p>\n");
if (tableMap != null && tableMap.get("comment") != null) {
code.append(" * ").append(tableMap.get("comment")).append(" 服务实现类\n");
}
code.append(" * </p>\n");
code.append(" *\n");
code.append(" * @author ").append(author).append("\n");
code.append(" * @since ").append(date).append("\n");
code.append(" */\n");
// 注解和类声明
code.append("@Service\n");
code.append("public class ").append(entity).append("ServiceImpl extends ServiceImpl<").append(entity).append("Mapper, ").append(entity).append("> implements I").append(entity).append("Service {\n\n");
code.append("}\n");
return code.toString();
}
/**
* 生成Mapper接口代码
*/
private String generateMapperCode(Map<String, Object> dataModel) {
private String generateMapperJavaCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
@SuppressWarnings("unchecked")
Map<String, String> packageMap = (Map<String, String>) dataModel.get("package");
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
String entity = safeString(dataModel.get("entity"));
String author = safeString(dataModel.get("author"));
String date = safeString(dataModel.get("date"));
@SuppressWarnings("unchecked")
Map<String, Object> tableMap = (Map<String, Object>) dataModel.get("table");
// 包声明
if (packageMap != null && packageMap.get("Mapper") != null) {
code.append("package ").append(packageMap.get("Mapper")).append(";\n\n");
@@ -698,6 +554,16 @@ import java.util.Scanner;
return xml.toString();
}
/**
* 生成默认代码
*/
private String generateDefaultCode(Map<String, Object> dataModel) {
StringBuilder code = new StringBuilder();
code.append("// 默认生成的代码\n");
code.append("// 请检查模板文件是否存在\n");
return code.toString();
}
/**
* 获取JDBC类型
*/

View File

@@ -0,0 +1,308 @@
package com.yexuejc.db2java.core.utils;
import com.yexuejc.db2java.core.generator.FieldInfo;
import com.yexuejc.db2java.core.generator.GenerationConfig;
import com.yexuejc.db2java.core.generator.TableInfo;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 数据库工具类
* 用于获取数据库表结构信息
*
* @author yexuejc
* @since 2025-01
*/
public class DatabaseUtils {
/**
* 获取数据库中所有表的信息
*
* @param connection 数据库连接
* @param config 生成配置
* @return 表信息列表
* @throws SQLException SQL异常
*/
public static List<TableInfo> getTableInfos(Connection connection, GenerationConfig config) throws SQLException {
List<TableInfo> tableInfos = new ArrayList<>();
DatabaseMetaData metaData = connection.getMetaData();
String catalog = connection.getCatalog();
String schemaPattern = null;
// 获取所有表
try (ResultSet tables = metaData.getTables(catalog, schemaPattern, null, new String[]{"TABLE"})) {
while (tables.next()) {
String tableName = tables.getString("TABLE_NAME");
// 检查表名是否有效
if (tableName == null || tableName.trim().isEmpty()) {
continue;
}
// 检查是否应该忽略此表
if (shouldIgnoreTable(tableName, config)) {
continue;
}
// 检查是否只包含特定表
if (config.getIncludeTables() != null && config.getIncludeTables().length > 0) {
boolean shouldInclude = false;
for (String includeTable : config.getIncludeTables()) {
if (includeTable.equalsIgnoreCase(tableName)) {
shouldInclude = true;
break;
}
}
if (!shouldInclude) {
continue;
}
}
TableInfo tableInfo = getTableInfo(metaData, catalog, schemaPattern, tableName, config);
if (tableInfo != null && tableInfo.getEntityName() != null && !tableInfo.getEntityName().trim().isEmpty()) {
tableInfos.add(tableInfo);
}
}
}
return tableInfos;
}
/**
* 获取单个表的信息
*
* @param metaData 数据库元数据
* @param catalog 数据库目录
* @param schemaPattern schema模式
* @param tableName 表名
* @param config 生成配置
* @return 表信息
* @throws SQLException SQL异常
*/
private static TableInfo getTableInfo(DatabaseMetaData metaData, String catalog, String schemaPattern, String tableName, GenerationConfig config) throws SQLException {
// 检查表名是否有效
if (tableName == null || tableName.trim().isEmpty()) {
return null;
}
TableInfo tableInfo = new TableInfo();
tableInfo.setTableName(tableName);
tableInfo.setEntityName(toPascalCase(tableName)); // 表名转换为大驼峰命名
// 获取表注释
try (ResultSet tableRs = metaData.getTables(catalog, schemaPattern, tableName, null)) {
if (tableRs.next()) {
tableInfo.setTableComment(tableRs.getString("REMARKS"));
}
}
// 获取字段信息
List<FieldInfo> fields = new ArrayList<>();
try (ResultSet columns = metaData.getColumns(catalog, schemaPattern, tableName, null)) {
while (columns.next()) {
String columnName = columns.getString("COLUMN_NAME");
String columnType = columns.getString("TYPE_NAME");
String remarks = columns.getString("REMARKS");
int dataType = columns.getInt("DATA_TYPE");
int columnSize = columns.getInt("COLUMN_SIZE");
int decimalDigits = columns.getInt("DECIMAL_DIGITS");
boolean isNullable = "YES".equals(columns.getString("IS_NULLABLE"));
String columnDef = columns.getString("COLUMN_DEF");
int ordinalPosition = columns.getInt("ORDINAL_POSITION");
// 检查字段名是否有效
if (columnName == null || columnName.trim().isEmpty()) {
continue;
}
FieldInfo fieldInfo = new FieldInfo();
fieldInfo.setColumnName(columnName);
fieldInfo.setColumnType(columnType);
fieldInfo.setColumnComment(remarks);
// 根据fieldNaming配置决定属性名
String fieldNaming = getFieldNaming(config);
if ("camelCase".equals(fieldNaming)) {
fieldInfo.setPropertyName(toCamelCase(columnName)); // 字段名转换为小驼峰命名
} else {
fieldInfo.setPropertyName(columnName);
}
// 使用TypeMappingConfig进行类型映射
fieldInfo.setPropertyType(TypeMappingConfig.getJavaType(columnType));
// 设置其他属性
fieldInfo.setLength(columnSize);
fieldInfo.setScale(decimalDigits);
fieldInfo.setNullable(isNullable);
fields.add(fieldInfo);
}
}
tableInfo.setFields(fields);
return tableInfo;
}
/**
* 从配置中获取字段命名策略
*
* @param config 生成配置
* @return 字段命名策略默认为camelCase
*/
private static String getFieldNaming(GenerationConfig config) {
if (config != null && config.getExtraConfig() != null) {
Map<String, Object> extraConfig = config.getExtraConfig();
Object fieldNamingObj = extraConfig.get("fieldNaming");
if (fieldNamingObj != null) {
return fieldNamingObj.toString();
}
}
return "camelCase"; // 默认使用驼峰命名
}
/**
* 将下划线命名转换为大驼峰命名(首字母大写)
*
* @param name 名称,如 user_name
* @return 大驼峰命名,如 UserName
*/
private static String toPascalCase(String name) {
if (name == null || name.isEmpty()) {
return "Unknown"; // 返回默认名称而不是null
}
StringBuilder result = new StringBuilder();
boolean nextUpperCase = true; // 首字母大写
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
result.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
result.append(Character.toLowerCase(c));
}
}
}
// 如果结果为空或无效,返回默认名称
String entityName = result.toString();
if (entityName.isEmpty()) {
return "Unknown";
}
// 检查是否是Java关键字如果是则添加前缀
if (isJavaKeyword(entityName)) {
return "Table" + entityName;
}
return entityName;
}
/**
* 将下划线命名转换为小驼峰命名(首字母小写)
*
* @param name 名称,如 user_name
* @return 小驼峰命名,如 userName
*/
private static String toCamelCase(String name) {
if (name == null || name.isEmpty()) {
return "unknown"; // 返回默认名称而不是null
}
StringBuilder result = new StringBuilder();
boolean nextUpperCase = false;
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
result.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
if (result.length() == 0) {
result.append(Character.toLowerCase(c)); // 首字母小写
} else {
result.append(Character.toLowerCase(c));
}
}
}
}
// 如果结果为空或无效,返回默认名称
String propertyName = result.toString();
if (propertyName.isEmpty()) {
return "unknown";
}
// 检查是否是Java关键字如果是则添加前缀
if (isJavaKeyword(propertyName)) {
return "field" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
}
return propertyName;
}
/**
* 检查是否是Java关键字
*
* @param name 名称
* @return 是否是Java关键字
*/
private static boolean isJavaKeyword(String name) {
if (name == null || name.isEmpty()) {
return false;
}
// 常见的Java关键字列表
String[] keywords = {
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"const", "continue", "default", "do", "double", "else", "enum", "extends", "final",
"finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",
"interface", "long", "native", "new", "null", "package", "private", "protected",
"public", "return", "short", "static", "strictfp", "super", "switch", "synchronized",
"this", "throw", "throws", "transient", "try", "void", "volatile", "while", "true",
"false"
};
for (String keyword : keywords) {
if (keyword.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
/**
* 检查表是否应该被忽略
*
* @param tableName 表名
* @param config 生成配置
* @return 是否应该忽略
*/
private static boolean shouldIgnoreTable(String tableName, GenerationConfig config) {
if (config.getIgnoreTables() != null) {
for (String ignoreTable : config.getIgnoreTables()) {
if (ignoreTable.equalsIgnoreCase(tableName)) {
return true;
}
}
}
return false;
}
// 删除原来的mapDataType方法因为现在使用TypeMappingConfig类
}

View File

@@ -0,0 +1,157 @@
package com.yexuejc.db2java.core.utils;
import java.util.HashMap;
import java.util.Map;
/**
* 数据库类型到Java类型的映射配置类
* 可维护的类型映射配置,支持多种数据库类型映射
*
* @author yexuejc
* @since 2025-01
*/
public class TypeMappingConfig {
/**
* 数据库类型到Java类型的映射表
*/
private static final Map<String, String> TYPE_MAPPING = new HashMap<>();
static {
// MySQL类型映射
TYPE_MAPPING.put("VARCHAR", "String");
TYPE_MAPPING.put("CHAR", "String");
TYPE_MAPPING.put("TEXT", "String");
TYPE_MAPPING.put("TINYTEXT", "String");
TYPE_MAPPING.put("MEDIUMTEXT", "String");
TYPE_MAPPING.put("LONGTEXT", "String");
TYPE_MAPPING.put("INT", "Integer");
TYPE_MAPPING.put("INTEGER", "Integer");
TYPE_MAPPING.put("TINYINT", "Integer");
TYPE_MAPPING.put("SMALLINT", "Integer");
TYPE_MAPPING.put("MEDIUMINT", "Integer");
TYPE_MAPPING.put("BIGINT", "Long");
TYPE_MAPPING.put("DECIMAL", "BigDecimal");
TYPE_MAPPING.put("NUMERIC", "BigDecimal");
TYPE_MAPPING.put("DATE", "LocalDate");
TYPE_MAPPING.put("TIME", "LocalTime");
TYPE_MAPPING.put("DATETIME", "LocalDateTime");
TYPE_MAPPING.put("TIMESTAMP", "LocalDateTime");
TYPE_MAPPING.put("BOOLEAN", "Boolean");
TYPE_MAPPING.put("BIT", "Boolean");
TYPE_MAPPING.put("FLOAT", "Float");
TYPE_MAPPING.put("DOUBLE", "Double");
TYPE_MAPPING.put("REAL", "Double");
// PostgreSQL类型映射
TYPE_MAPPING.put("CHARACTER VARYING", "String");
TYPE_MAPPING.put("CHARACTER", "String");
TYPE_MAPPING.put("TEXT", "String");
TYPE_MAPPING.put("SMALLINT", "Integer");
TYPE_MAPPING.put("INTEGER", "Integer");
TYPE_MAPPING.put("BIGINT", "Long");
TYPE_MAPPING.put("DECIMAL", "BigDecimal");
TYPE_MAPPING.put("NUMERIC", "BigDecimal");
TYPE_MAPPING.put("DATE", "LocalDate");
TYPE_MAPPING.put("TIME", "LocalTime");
TYPE_MAPPING.put("TIMESTAMP", "LocalDateTime");
TYPE_MAPPING.put("TIMESTAMP WITHOUT TIME ZONE", "LocalDateTime");
TYPE_MAPPING.put("BOOLEAN", "Boolean");
TYPE_MAPPING.put("REAL", "Float");
TYPE_MAPPING.put("DOUBLE PRECISION", "Double");
// Oracle类型映射
TYPE_MAPPING.put("VARCHAR2", "String");
TYPE_MAPPING.put("NVARCHAR2", "String");
TYPE_MAPPING.put("CHAR", "String");
TYPE_MAPPING.put("NCHAR", "String");
TYPE_MAPPING.put("CLOB", "String");
TYPE_MAPPING.put("NUMBER", "BigDecimal");
TYPE_MAPPING.put("INTEGER", "Integer");
TYPE_MAPPING.put("DATE", "LocalDateTime");
TYPE_MAPPING.put("TIMESTAMP", "LocalDateTime");
// SQL Server类型映射
TYPE_MAPPING.put("NVARCHAR", "String");
TYPE_MAPPING.put("NCHAR", "String");
TYPE_MAPPING.put("NTEXT", "String");
TYPE_MAPPING.put("INT", "Integer");
TYPE_MAPPING.put("BIGINT", "Long");
TYPE_MAPPING.put("DECIMAL", "BigDecimal");
TYPE_MAPPING.put("NUMERIC", "BigDecimal");
TYPE_MAPPING.put("MONEY", "BigDecimal");
TYPE_MAPPING.put("SMALLMONEY", "BigDecimal");
TYPE_MAPPING.put("DATE", "LocalDate");
TYPE_MAPPING.put("DATETIME", "LocalDateTime");
TYPE_MAPPING.put("DATETIME2", "LocalDateTime");
TYPE_MAPPING.put("SMALLDATETIME", "LocalDateTime");
TYPE_MAPPING.put("BIT", "Boolean");
TYPE_MAPPING.put("FLOAT", "Double");
TYPE_MAPPING.put("REAL", "Float");
}
/**
* 获取数据库类型对应的Java类型
*
* @param dbType 数据库类型
* @return 对应的Java类型如果未找到则返回Object
*/
public static String getJavaType(String dbType) {
if (dbType == null || dbType.trim().isEmpty()) {
return "Object";
}
String upperDbType = dbType.trim().toUpperCase();
String javaType = TYPE_MAPPING.get(upperDbType);
// 如果没有找到精确匹配,尝试模糊匹配
if (javaType == null) {
for (Map.Entry<String, String> entry : TYPE_MAPPING.entrySet()) {
if (upperDbType.contains(entry.getKey()) || entry.getKey().contains(upperDbType)) {
javaType = entry.getValue();
break;
}
}
}
return javaType != null ? javaType : "Object";
}
/**
* 添加自定义类型映射
*
* @param dbType 数据库类型
* @param javaType Java类型
*/
public static void addTypeMapping(String dbType, String javaType) {
if (dbType != null && javaType != null) {
TYPE_MAPPING.put(dbType.toUpperCase(), javaType);
}
}
/**
* 获取所有类型映射
*
* @return 类型映射表的副本
*/
public static Map<String, String> getAllTypeMappings() {
return new HashMap<>(TYPE_MAPPING);
}
}

View File

@@ -58,31 +58,43 @@ public class ${entity} {
<% } %>
<% /** -----------END 字段循环遍历----------- **/ %>
<% /** -----------BEGIN 一对一关联字段----------- **/ %>
<% if(isNotEmpty(table.oneToOneFields)){ %>
<% for(field in table.oneToOneFields){ %>
<% if(isNotEmpty(field.comment)){ %>
/**
* ${field.comment}
*/
<% } %>
<% if(isNotEmpty(field.annotationAttributesList)){ %>
<% for(an in field.annotationAttributesList){ %>
${an.displayName}
<% } %>
<% } %>
private ${field.propertyType} ${field.propertyName};
<% } %>
<% } %>
<% /** -----------END 一对一关联字段----------- **/ %>
<% /** -----------BEGIN 一对多关联字段----------- **/ %>
<% if(isNotEmpty(table.oneToManyFields)){ %>
<% for(field in table.oneToManyFields){ %>
<% if(isNotEmpty(field.comment)){ %>
/**
* ${field.comment}
*/
<% } %>
<% if(isNotEmpty(field.annotationAttributesList)){ %>
<% for(an in field.annotationAttributesList){ %>
${an.displayName}
<% } %>
private java.util.List<${field.propertyType}> ${field.propertyName};
<% } %>
private List<${field.propertyType}> ${field.propertyName};
<% } %>
<% } %>
<% /** -----------END 一对多关联字段----------- **/ %>
<% if(!entityLombokModel){ %>
<% for(field in table.fields){ %>

View File

@@ -54,6 +54,42 @@ public class ${entity} {
private ${field.propertyType} ${field.propertyName};
</#list>
<#------------ END 字段循环遍历 ---------->
<#-- ---------- BEGIN 一对一关联字段 ---------->
<#if table.oneToOneFields??>
<#list table.oneToOneFields as field>
<#if field.comment!?length gt 0>
/**
* ${field.comment}
*/
</#if>
<#if field.annotationAttributesList??>
<#list field.annotationAttributesList as an>
${an.displayName}
</#list>
</#if>
private ${field.propertyType} ${field.propertyName};
</#list>
</#if>
<#-- ---------- END 一对一关联字段 ---------->
<#-- ---------- BEGIN 一对多关联字段 ---------->
<#if table.oneToManyFields??>
<#list table.oneToManyFields as field>
<#if field.comment!?length gt 0>
/**
* ${field.comment}
*/
</#if>
<#if field.annotationAttributesList??>
<#list field.annotationAttributesList as an>
${an.displayName}
</#list>
</#if>
private java.util.List<${field.propertyType}> ${field.propertyName};
</#list>
</#if>
<#-- ---------- END 一对多关联字段 ---------->
<#if !entityLombokModel>
<#list table.fields as field>
<#if field.propertyType == "boolean">

View File

@@ -59,12 +59,16 @@ public class ${entity} {
#if(${table.oneToOneFields})
#foreach($field in ${table.oneToOneFields})
#if("$!field.comment" != "")
/**
* ${field.comment}
*/
#foreach($an in ${field.annotationAttributesList})
#end
#if(${field.annotationAttributesList})
#foreach($an in ${field.annotationAttributesList})
${an.displayName}
#end
#end
#end
private ${field.propertyType} ${field.propertyName};
#end
#end
@@ -74,13 +78,17 @@ public class ${entity} {
#if(${table.oneToManyFields})
#foreach($field in ${table.oneToManyFields})
#if("$!field.comment" != "")
/**
* ${field.comment}
*/
#foreach($an in ${field.annotationAttributesList})
#end
#if(${field.annotationAttributesList})
#foreach($an in ${field.annotationAttributesList})
${an.displayName}
#end
private java.util.List<${field.propertyType}> ${field.propertyName};
#end
#end
private List<${field.propertyType}> ${field.propertyName};
#end
#end
## ---------- END 一对多关联字段 ----------

View File

@@ -0,0 +1,52 @@
package com.yexuejc.db2java.core;
import com.yexuejc.db2java.core.generator.GenerationConfig;
import com.yexuejc.db2java.core.generator.GenerationResult;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class MysqlDb2JavaCoreTest {
@Test
void generate() throws Exception {
// 创建配置对象并设置相关属性
GenerationConfig config = new GenerationConfig();
config.setUrl("jdbc:mysql://192.168.0.107:3306/globalVoice?characterEncoding=utf8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true");
config.setUsername("intasect");
config.setPassword("2$hGv1Dz[3)J7]BS]");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMode("mybatis-plus");
config.setType("coding");
config.setOutDir("C:/0110_Workspace/yexuejc/db2java/export");
config.setPackageName("top.yexuejc.abc");
config.setAuthor("yexuejc");
config.setLombok(false);
config.setMerge(true);
config.setOverride(true);
config.setEngine("freemarker");
config.setExtraConfig(Map.of("fieldNaming","camelCase"));
// 设置忽略表列表
config.setIgnoreTables(List.of("sys_user", "sys_role", "sys_role_user").toArray(new String[0]));
// 设置忽略字段列表
config.setIgnoreColumns(List.of("create_time", "update_time").toArray(new String[0]));
// 设置包含表列表
// config.setIncludeTables(List.of("sys_user", "sys_role", "sys_role_user").toArray(new String[0]));
// 执行代码生成
GenerationResult result = Db2JavaCore.generate(config);
System.out.println(result);
// 验证结果不为空
assertNotNull(result);
}
}

View File

@@ -28,27 +28,27 @@ public class Db2JavaExample {
// 测试生成标准的Java代码
// 设置为coding模式生成标准的src/main/java结构
testImprovedGeneration(tableInfos, "freemarker", "mybatis", true,"coding");// 基本的OK
testImprovedGeneration(tableInfos, "freemarker", "mybatis", false,"coding");// 基本的OK
testImprovedGeneration(tableInfos, "freemarker", "mybatis", false,"file");// 基本的OK
testImprovedGeneration(tableInfos, "freemarker", "mybatis-plus", true,"coding");// 基本的OK
testImprovedGeneration(tableInfos, "freemarker", "jpa", false,"coding");// 测试不使用Lombok的情况
testImprovedGeneration(tableInfos, "freemarker", "jpa", true,"coding");// 基本的OK
// testImprovedGeneration(tableInfos, "freemarker", "mybatis", false,"coding");// 基本的OK
// testImprovedGeneration(tableInfos, "freemarker", "mybatis", false,"file");// 基本的OK
// testImprovedGeneration(tableInfos, "freemarker", "mybatis-plus", true,"coding");// 基本的OK
// testImprovedGeneration(tableInfos, "freemarker", "jpa", false,"coding");// 测试不使用Lombok的情况
// testImprovedGeneration(tableInfos, "freemarker", "jpa", true,"coding");// 基本的OK
// velocity,beetl,enjoy
testImprovedGeneration(tableInfos, "velocity", "mybatis", true,"coding");
testImprovedGeneration(tableInfos, "velocity", "mybatis", false,"coding");
testImprovedGeneration(tableInfos, "velocity", "mybatis", false,"file");
testImprovedGeneration(tableInfos, "velocity", "mybatis-plus", true,"coding");
testImprovedGeneration(tableInfos, "velocity", "hibernate", false,"coding");
testImprovedGeneration(tableInfos, "velocity", "jpa", true,"coding");
// testImprovedGeneration(tableInfos, "velocity", "mybatis", false,"coding");
// testImprovedGeneration(tableInfos, "velocity", "mybatis", false,"file");
// testImprovedGeneration(tableInfos, "velocity", "mybatis-plus", true,"coding");
// testImprovedGeneration(tableInfos, "velocity", "hibernate", false,"coding");
// testImprovedGeneration(tableInfos, "velocity", "jpa", true,"coding");
testImprovedGeneration(tableInfos, "beetl", "mybatis", true,"coding");
testImprovedGeneration(tableInfos, "beetl", "mybatis", false,"coding");
testImprovedGeneration(tableInfos, "beetl", "mybatis", false,"file");
testImprovedGeneration(tableInfos, "beetl", "mybatis-plus", true,"coding");
testImprovedGeneration(tableInfos, "beetl", "hibernate", false,"coding");
testImprovedGeneration(tableInfos, "beetl", "jpa", true,"coding");
// testImprovedGeneration(tableInfos, "beetl", "mybatis", false,"coding");
// testImprovedGeneration(tableInfos, "beetl", "mybatis", false,"file");
// testImprovedGeneration(tableInfos, "beetl", "mybatis-plus", true,"coding");
// testImprovedGeneration(tableInfos, "beetl", "hibernate", false,"coding");
// testImprovedGeneration(tableInfos, "beetl", "jpa", true,"coding");
} catch (Exception e) {
System.err.println("生成代码时发生错误: " + e.getMessage());

View File

@@ -2,116 +2,83 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.yexuejc</groupId>
<artifactId>db2java-web</artifactId>
<version>1.0-SNAPSHOT</version>
<name>db2java-web</name>
<description>Web interface for db2java code generation tool</description>
<properties>
<compiler-plugin.version>3.14.0</compiler-plugin.version>
<maven.compiler.release>24</maven.compiler.release>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.26.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.3</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot Starter Web with Undertow -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- Spring Boot Thymeleaf for UI -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Boot Configuration Processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- db2java-core dependency -->
<dependency>
<groupId>top.yexuejc</groupId>
<artifactId>db2java-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
<goal>native-image-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,11 @@
package com.yexuejc.db2java.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,46 @@
package com.yexuejc.db2java.web.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
private String driverClassName;
// Getters and Setters
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
}

View File

@@ -0,0 +1,272 @@
package com.yexuejc.db2java.web.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "generate")
public class GenerateProperties {
private String mode;
private String type;
private String out;
private String packageName;
private String author;
private boolean lombok;
private boolean merge;
private boolean override;
private String engine;
private List<String> ignoreTable;
private List<String> ignoreColumn;
private List<String> includeTable;
private Entity entity = new Entity();
private Controller controller = new Controller();
public static class Entity {
private boolean serialVersionUID;
private boolean serialAnnotation;
private boolean columnConstant;
private boolean chainModel;
private boolean toString;
private boolean fieldUseJavaDoc;
private boolean activeRecord;
private boolean serializable;
private boolean equalsAndHashCode;
private String fieldNaming;
private String tableAnnotation;
// Getters and Setters
public boolean isSerialVersionUID() {
return serialVersionUID;
}
public void setSerialVersionUID(boolean serialVersionUID) {
this.serialVersionUID = serialVersionUID;
}
public boolean isSerialAnnotation() {
return serialAnnotation;
}
public void setSerialAnnotation(boolean serialAnnotation) {
this.serialAnnotation = serialAnnotation;
}
public boolean isColumnConstant() {
return columnConstant;
}
public void setColumnConstant(boolean columnConstant) {
this.columnConstant = columnConstant;
}
public boolean isChainModel() {
return chainModel;
}
public void setChainModel(boolean chainModel) {
this.chainModel = chainModel;
}
public boolean isToString() {
return toString;
}
public void setToString(boolean toString) {
this.toString = toString;
}
public boolean isFieldUseJavaDoc() {
return fieldUseJavaDoc;
}
public void setFieldUseJavaDoc(boolean fieldUseJavaDoc) {
this.fieldUseJavaDoc = fieldUseJavaDoc;
}
public boolean isActiveRecord() {
return activeRecord;
}
public void setActiveRecord(boolean activeRecord) {
this.activeRecord = activeRecord;
}
public boolean isSerializable() {
return serializable;
}
public void setSerializable(boolean serializable) {
this.serializable = serializable;
}
public boolean isEqualsAndHashCode() {
return equalsAndHashCode;
}
public void setEqualsAndHashCode(boolean equalsAndHashCode) {
this.equalsAndHashCode = equalsAndHashCode;
}
public String getFieldNaming() {
return fieldNaming;
}
public void setFieldNaming(String fieldNaming) {
this.fieldNaming = fieldNaming;
}
public String getTableAnnotation() {
return tableAnnotation;
}
public void setTableAnnotation(String tableAnnotation) {
this.tableAnnotation = tableAnnotation;
}
}
public static class Controller {
private boolean mappingHyphen;
private boolean restStyle;
private String superClass;
// Getters and Setters
public boolean isMappingHyphen() {
return mappingHyphen;
}
public void setMappingHyphen(boolean mappingHyphen) {
this.mappingHyphen = mappingHyphen;
}
public boolean isRestStyle() {
return restStyle;
}
public void setRestStyle(boolean restStyle) {
this.restStyle = restStyle;
}
public String getSuperClass() {
return superClass;
}
public void setSuperClass(String superClass) {
this.superClass = superClass;
}
}
// Getters and Setters
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getOut() {
return out;
}
public void setOut(String out) {
this.out = out;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public boolean isLombok() {
return lombok;
}
public void setLombok(boolean lombok) {
this.lombok = lombok;
}
public boolean isMerge() {
return merge;
}
public void setMerge(boolean merge) {
this.merge = merge;
}
public boolean isOverride() {
return override;
}
public void setOverride(boolean override) {
this.override = override;
}
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public List<String> getIgnoreTable() {
return ignoreTable;
}
public void setIgnoreTable(List<String> ignoreTable) {
this.ignoreTable = ignoreTable;
}
public List<String> getIgnoreColumn() {
return ignoreColumn;
}
public void setIgnoreColumn(List<String> ignoreColumn) {
this.ignoreColumn = ignoreColumn;
}
public List<String> getIncludeTable() {
return includeTable;
}
public void setIncludeTable(List<String> includeTable) {
this.includeTable = includeTable;
}
public Entity getEntity() {
return entity;
}
public void setEntity(Entity entity) {
this.entity = entity;
}
public Controller getController() {
return controller;
}
public void setController(Controller controller) {
this.controller = controller;
}
}

View File

@@ -0,0 +1,168 @@
package com.yexuejc.db2java.web.controller;
import com.yexuejc.db2java.core.Db2JavaCore;
import com.yexuejc.db2java.core.generator.GenerationConfig;
import com.yexuejc.db2java.core.generator.GenerationResult;
import com.yexuejc.db2java.web.config.DataSourceProperties;
import com.yexuejc.db2java.web.config.GenerateProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Controller
public class CodeGeneratorController {
@Autowired
private DataSourceProperties dataSourceProperties;
@Autowired
private GenerateProperties generateProperties;
@GetMapping("/")
public String index(Model model) {
model.addAttribute("dataSourceProperties", dataSourceProperties);
model.addAttribute("generateProperties", generateProperties);
String separator = System.lineSeparator();
model.addAttribute("separator", separator);
return "index";
}
@PostMapping("/generate")
public String generateCode(
@RequestParam String url,
@RequestParam String username,
@RequestParam String password,
@RequestParam String driverClassName,
@RequestParam String mode,
@RequestParam String type,
@RequestParam String out,
@RequestParam String packageName,
@RequestParam String author,
@RequestParam(defaultValue = "false") boolean lombok,
@RequestParam(defaultValue = "false") boolean merge,
@RequestParam(defaultValue = "false") boolean override,
@RequestParam String engine,
@RequestParam(required = false) String ignoreTable,
@RequestParam(required = false) String ignoreColumn,
@RequestParam(required = false) String includeTable,
RedirectAttributes redirectAttributes) {
System.out.println("接收到代码生成请求,参数如下:");
System.out.println("数据库URL: " + url);
System.out.println("数据库用户名: " + username);
System.out.println("数据库驱动类名: " + driverClassName);
System.out.println("生成模式: " + mode);
System.out.println("生成代码模式: " + type);
System.out.println("输出目录: " + out);
System.out.println("包名: " + packageName);
System.out.println("作者: " + author);
System.out.println("是否启用Lombok: " + lombok);
System.out.println("是否启用合并模式: " + merge);
System.out.println("是否覆盖文件: " + override);
System.out.println("模板引擎: " + engine);
System.out.println("忽略表列表: " + ignoreTable);
System.out.println("忽略字段列表: " + ignoreColumn);
System.out.println("包含表列表: " + includeTable);
System.out.println("===========================================");
try {
// 更新配置
dataSourceProperties.setUrl(url);
dataSourceProperties.setUsername(username);
dataSourceProperties.setPassword(password);
dataSourceProperties.setDriverClassName(driverClassName);
generateProperties.setMode(mode);
generateProperties.setType(type);
generateProperties.setOut(out);
generateProperties.setPackageName(packageName);
generateProperties.setAuthor(author);
generateProperties.setLombok(lombok);
generateProperties.setMerge(merge);
generateProperties.setOverride(override);
generateProperties.setEngine(engine);
generateProperties.setIgnoreTable(ignoreTable != null && !ignoreTable.isEmpty() ?
Arrays.asList(ignoreTable.split("[\\r\\n]+")) : null);
generateProperties.setIgnoreColumn(ignoreColumn != null && !ignoreColumn.isEmpty() ?
Arrays.asList(ignoreColumn.split("[\\r\\n]+")) : null);
generateProperties.setIncludeTable(includeTable != null && !includeTable.isEmpty() ?
Arrays.asList(includeTable.split("[\\r\\n]+")) : null);
// 创建生成配置
GenerationConfig config = new GenerationConfig();
config.setUrl(url);
config.setUsername(username);
config.setPassword(password);
config.setDriverClassName(driverClassName);
config.setMode(mode);
config.setType(type);
config.setOutDir(out);
config.setPackageName(packageName);
config.setAuthor(author);
config.setLombok(lombok);
config.setMerge(merge);
config.setOverride(override);
config.setEngine(engine);
// 处理忽略表列表
if (ignoreTable != null && !ignoreTable.isEmpty()) {
List<String> ignoreTableList = Arrays.stream(ignoreTable.split("[\\r\\n]+"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
config.setIgnoreTables(ignoreTableList.toArray(new String[0]));
} else {
config.setIgnoreTables(new String[0]);
}
// 处理忽略字段列表
if (ignoreColumn != null && !ignoreColumn.isEmpty()) {
List<String> ignoreColumnList = Arrays.stream(ignoreColumn.split("[\\r\\n]+"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
config.setIgnoreColumns(ignoreColumnList.toArray(new String[0]));
} else {
config.setIgnoreColumns(new String[0]);
}
// 处理包含表列表
if (includeTable != null && !includeTable.isEmpty()) {
List<String> includeTableList = Arrays.stream(includeTable.split("[\\r\\n]+"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
config.setIncludeTables(includeTableList.toArray(new String[0]));
} else {
config.setIncludeTables(new String[0]);
}
// 设置额外配置,包括字段命名策略
Map<String, Object> extraConfig = new HashMap<>();
extraConfig.put("fieldNaming", generateProperties.getEntity().getFieldNaming());
config.setExtraConfig(extraConfig);
// 执行代码生成
GenerationResult result = Db2JavaCore.generate(config);
redirectAttributes.addFlashAttribute("success", "代码生成成功!共生成 " + result.getGeneratedFiles().size() + " 个文件。");
} catch (Exception e) {
System.err.println("代码生成失败: " + e.getMessage());
e.printStackTrace();
redirectAttributes.addFlashAttribute("error", "代码生成失败: " + e.getMessage());
}
return "redirect:/";
}
}

View File

@@ -0,0 +1,88 @@
server:
port: 8080
undertow:
# 设置IO线程数, 它主要执行非阻塞的任务, 它们会负责多个连接
io-threads: 4
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程
worker-threads: 20
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
buffer-size: 1024
# 是否分配的直接内存
direct-buffers: true
# 数据库配置
datasource:
url: jdbc:mysql://192.168.0.107:3306/globalVoice?characterEncoding=utf8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true
username: intasect
password: 2$hGv1Dz[3)J7]BS]
driver-class-name: com.mysql.cj.jdbc.Driver
# 生成配置信息
generate:
# 生成模式hibernate,jpa,mybatis,mybatis-plus
mode: mybatis-plus
# 生成代码模式 file(直接在指定目录下生成代码),coding(在目录下生成/src/main/java和对应的package路径)
type: coding
# 输出目录
out: C:/0110_Workspace/yexuejc/db2java/export
# 包名
package: com.yexuejc.db2java.export
# 作者
author: yexuejc
# lombok模式 - 启用后不生成getter/setter方法使用@Data注解
lombok: false
# merge模式 - 是否合并已存在的文件
merge: true
# 覆盖已存在文件
override: true
# 模板引擎freemarker,velocity,beetl,enjoy
engine: freemarker
# 忽略表
ignore-table:
- sys_user
- sys_role
- sys_role_user
# 忽略字段
ignore-column:
- create_time
- update_time
# 包含表
include-table:
- sys_user
- sys_role
- sys_role_user
# 实体类配置
entity:
# 是否生成序列化版本ID
serialVersionUID: true
# 是否使用Serial注解(Java 14+)
serialAnnotation: false
# 是否生成字段常量
columnConstant: false
# 是否启用链式模型(返回this)
chainModel: false
# 是否生成toString方法(lombok=false时有效)
toString: true
# 是否使用JavaDoc注释字段
fieldUseJavaDoc: true
# 是否启用ActiveRecord模式
activeRecord: false
# 是否实现Serializable接口
serializable: true
# 是否生成equals和hashCode方法
equalsAndHashCode: false
# 字段命名策略: camelCase(驼峰), underline(下划线)
fieldNaming: camelCase
# 表名注解策略: none(无注解), table(使用@Table), entity(使用@Entity)
tableAnnotation: none
controller:
# 驼峰转连字符(默认 false
## <code>@RequestMapping("/managerUserActionHistory")</code> -> <code>@RequestMapping("/manager-user-action-history")</code>
mappingHyphen: true
# 生成 <code>@RestController</code> 控制器(默认 false
## <code>@Controller</code> -> <code>@RestController</code>
restStyle: true
# 自定义继承的Controller类全称带包名,默认为空
## superClass: com.yexuejc.db2java.export.controller.BaseController
superClass:

View File

@@ -0,0 +1,179 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DB2Java代码生成器</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">DB2Java代码生成器</h1>
<!-- 显示成功或错误消息 -->
<div th:if="${success}" class="alert alert-success alert-dismissible fade show" role="alert">
<span th:text="${success}"></span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div th:if="${error}" class="alert alert-danger alert-dismissible fade show" role="alert">
<span th:text="${error}"></span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<form action="/generate" method="post">
<div class="card mb-4">
<div class="card-header">
<h5>数据库配置</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="url" class="form-label">数据库URL</label>
<input type="text" class="form-control" id="url" name="url"
th:value="${dataSourceProperties.url}" required>
</div>
<div class="col-md-6 mb-3">
<label for="driverClassName" class="form-label">驱动类名</label>
<input type="text" class="form-control" id="driverClassName" name="driverClassName"
th:value="${dataSourceProperties.driverClassName}" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" name="username"
th:value="${dataSourceProperties.username}" required>
</div>
<div class="col-md-6 mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" name="password"
th:value="${dataSourceProperties.password}" required>
</div>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header">
<h5>生成配置</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label for="mode" class="form-label">生成模式</label>
<select class="form-select" id="mode" name="mode" required>
<option value="hibernate" th:selected="${generateProperties.mode == 'hibernate'}">
Hibernate
</option>
<option value="jpa" th:selected="${generateProperties.mode == 'jpa'}">JPA</option>
<option value="mybatis" th:selected="${generateProperties.mode == 'mybatis'}">MyBatis
</option>
<option value="mybatis-plus" th:selected="${generateProperties.mode == 'mybatis-plus'}">
MyBatis-Plus
</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="type" class="form-label">生成代码模式</label>
<select class="form-select" id="type" name="type" required>
<option value="file" th:selected="${generateProperties.type == 'file'}">File</option>
<option value="coding" th:selected="${generateProperties.type == 'coding'}">Coding</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="out" class="form-label">输出目录</label>
<input type="text" class="form-control" id="out" name="out"
th:value="${generateProperties.out}" required>
</div>
<div class="col-md-6 mb-3">
<label for="packageName" class="form-label">包名</label>
<input type="text" class="form-control" id="packageName" name="packageName"
th:value="${generateProperties.packageName}" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="author" class="form-label">作者</label>
<input type="text" class="form-control" id="author" name="author"
th:value="${generateProperties.author}">
</div>
<div class="col-md-6 mb-3">
<label for="engine" class="form-label">模板引擎</label>
<select class="form-select" id="engine" name="engine" required>
<option value="freemarker" th:selected="${generateProperties.engine == 'freemarker'}">
FreeMarker
</option>
<option value="velocity" th:selected="${generateProperties.engine == 'velocity'}">Velocity
</option>
<option value="beetl" th:selected="${generateProperties.engine == 'beetl'}">Beetl</option>
<option value="enjoy" th:selected="${generateProperties.engine == 'enjoy'}">Enjoy</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-3 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="lombok" name="lombok"
th:checked="${generateProperties.lombok}">
<label class="form-check-label" for="lombok">启用Lombok</label>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="merge" name="merge"
th:checked="${generateProperties.merge}">
<label class="form-check-label" for="merge">合并模式</label>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="override" name="override"
th:checked="${generateProperties.override}">
<label class="form-check-label" for="override">覆盖文件</label>
</div>
</div>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header">
<h5>表和字段配置</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="includeTable" class="form-label">包含表(每行一个)</label>
<textarea class="form-control" id="includeTable" name="includeTable" rows="3"
th:text="${generateProperties?.includeTable != null ? #strings.listJoin(generateProperties.includeTable, separator) : ''}">
</textarea>
</div>
<div class="mb-3">
<label for="ignoreTable" class="form-label">忽略表(每行一个)</label>
<textarea class="form-control" id="ignoreTable" name="ignoreTable" rows="3"
th:text="${generateProperties?.ignoreTable != null ? #strings.listJoin(generateProperties.ignoreTable, separator) : ''}"></textarea>
</div>
<div class="mb-3">
<label for="ignoreColumn" class="form-label">忽略字段(每行一个)</label>
<textarea class="form-control" id="ignoreColumn" name="ignoreColumn" rows="3"
th:text="${generateProperties?.ignoreColumn != null ? #strings.listJoin(generateProperties.ignoreColumn, separator) : ''}"></textarea>
</div>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="submit" class="btn btn-primary btn-lg">生成代码</button>
</div>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

7
问题修改一览.csv Normal file
View File

@@ -0,0 +1,7 @@
问题点,对应方案,类似问题是否对应
HTML表单请求参数与接口定义不匹配导致400错误,将Controller中List<String>参数类型改为String并在代码中进行分割处理,
可选复选框参数缺失导致400错误,为lombok、merge、override参数添加@RequestParam(defaultValue = "false")注解,
换行符处理不一致,将字符串分割逻辑从"\\r?\\n"修改为"[\\r\\n]+"正则表达式,
字段命名策略未生效,在DatabaseUtils中正确获取和使用fieldNaming配置,
模板处理器接口实现不完整,添加templateExists方法实现并修复导入语句,
数据库字段和Java属性类型映射不正确,创建TypeMappingConfig配置类进行类型映射,
Can't render this file because it contains an unexpected character in line 3 and column 113.

8
问题修改一览.txt Normal file
View File

@@ -0,0 +1,8 @@
问题点,对应案,类似问题是否对应
1. HTML表单参数与Controller接口参数类型不匹配导致400错误,修改Controller中ignoreTable、ignoreColumn、includeTable参数类型从List<String>为String并在代码中进行分割处理,是
2. HTML表单中可选复选框未选中时不会发送参数导致400错误,为lombok、merge、override参数添加@RequestParam(defaultValue = "false")注解,是
3. 不同操作系统的换行符处理不一致,将字符串分割逻辑从"\\r?\\n"修改为"[\\r\\n]+"正则表达式,是
4. 字段命名策略配置未生效,修复DatabaseUtils中字段命名转换逻辑正确使用fieldNaming配置,是
5. 实体类名大小写不正确,class名应使用大驼峰命名修复DatabaseUtils中的toPascalCase方法,是
6. 无效表名导致生成null.java文件,增加表名有效性检查和默认名称处理机制,是
7. 模板引擎类名与文件名不一致,重构FreemarkerTemplateProcessor确保类名和文件名一致,是