From 6e76d30baca110ae7bd2651a55c9f4f10ccd1821 Mon Sep 17 00:00:00 2001 From: yexuejc <1107047387@qq.com> Date: Tue, 21 Oct 2025 23:51:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E8=BF=9E=E8=A1=A8=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=87=E4=BB=B6=EF=BC=8C=E4=BD=86=E6=98=AF=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .qoder/rules/project_rules.md | 111 ++++++ .qoder/rules/user_rules.md | 24 ++ .vscode/settings.json | 4 + db2java-core/pom.xml | 19 + .../com/yexuejc/db2java/core/Db2JavaCore.java | 40 ++ .../db2java/core/generator/FieldInfo.java | 65 ++++ .../core/generator/GenerationConfig.java | 57 +++ .../impl/HibernateCodeGenerator.java | 104 ++--- .../core/generator/impl/JpaCodeGenerator.java | 4 + .../generator/impl/MybatisCodeGenerator.java | 190 ++++----- .../impl/MybatisPlusCodeGenerator.java | 208 +++++----- .../impl/FreemarkerTemplateProcessor.java | 362 ++++++------------ .../db2java/core/utils/DatabaseUtils.java | 308 +++++++++++++++ .../db2java/core/utils/TypeMappingConfig.java | 157 ++++++++ .../main/resources/templates/entity.java.btl | 14 +- .../main/resources/templates/entity.java.ftl | 38 +- .../main/resources/templates/entity.java.vm | 18 +- .../db2java/core/MysqlDb2JavaCoreTest.java | 52 +++ .../src/test/java/example/Db2JavaExample.java | 32 +- db2java-web/pom.xml | 149 +++---- .../com/yexuejc/db2java/web/Application.java | 11 + .../web/config/DataSourceProperties.java | 46 +++ .../web/config/GenerateProperties.java | 272 +++++++++++++ .../controller/CodeGeneratorController.java | 168 ++++++++ .../src/main/resources/application.yml | 88 +++++ .../src/main/resources/templates/index.html | 179 +++++++++ 问题修改一览.csv | 7 + 问题修改一览.txt | 8 + 28 files changed, 2131 insertions(+), 604 deletions(-) create mode 100644 .qoder/rules/project_rules.md create mode 100644 .qoder/rules/user_rules.md create mode 100644 .vscode/settings.json create mode 100644 db2java-core/src/main/java/com/yexuejc/db2java/core/utils/DatabaseUtils.java create mode 100644 db2java-core/src/main/java/com/yexuejc/db2java/core/utils/TypeMappingConfig.java create mode 100644 db2java-core/src/test/java/com/yexuejc/db2java/core/MysqlDb2JavaCoreTest.java create mode 100644 db2java-web/src/main/java/com/yexuejc/db2java/web/Application.java create mode 100644 db2java-web/src/main/java/com/yexuejc/db2java/web/config/DataSourceProperties.java create mode 100644 db2java-web/src/main/java/com/yexuejc/db2java/web/config/GenerateProperties.java create mode 100644 db2java-web/src/main/java/com/yexuejc/db2java/web/controller/CodeGeneratorController.java create mode 100644 db2java-web/src/main/resources/application.yml create mode 100644 db2java-web/src/main/resources/templates/index.html create mode 100644 问题修改一览.csv create mode 100644 问题修改一览.txt diff --git a/.qoder/rules/project_rules.md b/.qoder/rules/project_rules.md new file mode 100644 index 0000000..2008ebd --- /dev/null +++ b/.qoder/rules/project_rules.md @@ -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格式输出首个决策检查点。 \ No newline at end of file diff --git a/.qoder/rules/user_rules.md b/.qoder/rules/user_rules.md new file mode 100644 index 0000000..6d89f98 --- /dev/null +++ b/.qoder/rules/user_rules.md @@ -0,0 +1,24 @@ +--- +trigger: always_on +alwaysApply: true +--- + +严格遵循阿里巴巴Java开发规范,包括但不限于: +- 命名规范 +- 代码格式 +- 注释规范 +- 异常处理规范 +- 数据库操作规范 +- 缓存操作规范 +- 日志记录规范 +- 性能优化规范 + +严格遵守JavaScript,Html,Css规范,包括但不限于: +- 命名规范 +- 代码格式 +- 注释规范 +- 异常处理规范 +- 数据库操作规范 +- 缓存操作规范 +- 日志记录规范 +- 性能优化规范 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b84f89c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/db2java-core/pom.xml b/db2java-core/pom.xml index a1e531d..0d53994 100644 --- a/db2java-core/pom.xml +++ b/db2java-core/pom.xml @@ -103,6 +103,25 @@ lombok 1.18.40 + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + example.Db2JavaExample + + + + + \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/Db2JavaCore.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/Db2JavaCore.java index 2851e05..974ceba 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/Db2JavaCore.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/Db2JavaCore.java @@ -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 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 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); } diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/FieldInfo.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/FieldInfo.java index df543dc..60e5a08 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/FieldInfo.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/FieldInfo.java @@ -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; + } } \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/GenerationConfig.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/GenerationConfig.java index aad2c9e..b10f1bf 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/GenerationConfig.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/GenerationConfig.java @@ -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; } diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/HibernateCodeGenerator.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/HibernateCodeGenerator.java index caa88c2..8a404fa 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/HibernateCodeGenerator.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/HibernateCodeGenerator.java @@ -5,27 +5,29 @@ 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.*; /** * Hibernate代码生成器 - * + * * @author yexuejc * @since 2025-01 */ +@Slf4j public class HibernateCodeGenerator implements CodeGenerator { - + @Override public GenerationMode getGenerationMode() { return GenerationMode.HIBERNATE; } - + @Override public GenerationResult generate(List tableInfos, GenerationConfig config) throws Exception { List generatedFiles = new ArrayList<>(); - + for (TableInfo tableInfo : tableInfos) { // 生成Hibernate Entity GeneratedFile entityFile = generateEntity(tableInfo, config); @@ -34,64 +36,65 @@ public class HibernateCodeGenerator implements CodeGenerator { writeFileToDisK(entityFile, config); } } - + return GenerationResult.success(generatedFiles); } - + @Override public List getSupportedFileTypes() { return Collections.singletonList("Entity"); } - + @Override public Map getTemplateFileMapping() { Map mapping = new HashMap<>(); mapping.put("Entity", "entity.java"); return mapping; } - + @Override public Map getOutputFileMapping() { Map mapping = new HashMap<>(); mapping.put("Entity", "{entityName}.java"); return mapping; } - + @Override public void initialize(GenerationConfig config) throws Exception { // Hibernate生成器初始化逻辑 System.out.println("Hibernate代码生成器初始化完成"); } - + private GeneratedFile generateEntity(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + ".java"; String filePath = buildFilePath(config, "entity", fileName); - + // 获取模板引擎处理器 TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); - + // 准备数据模型 Map dataModel = buildDataModel(tableInfo, config); - + // 处理模板 String templateName = "entity.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Entity", content); } catch (Exception e) { System.err.println("生成Hibernate Entity失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + /** * 构建文件路径,根据type配置决定路径结构 */ private String buildFilePath(GenerationConfig config, String subDir, String fileName) { String basePath = config.getOutputPath(); String type = config.getType(); - + if ("coding".equals(type)) { // coding模式:生成标准的src/main/java结构 String packagePath = config.getPackageName().replace(".", "/"); @@ -101,30 +104,30 @@ public class HibernateCodeGenerator implements CodeGenerator { return basePath + "/" + subDir + "/" + fileName; } } - + /** * 构建模板数据模型 */ private Map buildDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // 导入包 dataModel.put("importEntityFrameworkPackages", getEntityImports(config.isLombok())); dataModel.put("importEntityJavaPackages", getJavaImports(tableInfo)); - + // Lombok配置 dataModel.put("entityLombokModel", config.isLombok()); - + // 类注解(默认为空列表) dataModel.put("entityClassAnnotations", new ArrayList<>()); - + // 实体类配置 dataModel.put("superEntityClass", null); dataModel.put("activeRecord", false); @@ -134,30 +137,30 @@ public class HibernateCodeGenerator implements CodeGenerator { dataModel.put("entityColumnConstant", false); dataModel.put("entityToString", false); dataModel.put("entityFieldUseJavaDoc", true); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { // 序列化配置 dataModel.put("entitySerialVersionUID", extraConfig.getOrDefault("serialVersionUID", true)); dataModel.put("serializable", extraConfig.getOrDefault("serializable", true)); - + // toString配置 dataModel.put("entityToString", extraConfig.getOrDefault("toString", false)); - + // 字段相关配置 dataModel.put("fieldUseJavaDoc", extraConfig.getOrDefault("fieldUseJavaDoc", true)); - + // 类注解 dataModel.put("entityClassAnnotations", extraConfig.getOrDefault("entityClassAnnotations", new ArrayList<>())); - + // 实体类配置 dataModel.put("superEntityClass", extraConfig.get("superEntityClass")); dataModel.put("activeRecord", extraConfig.getOrDefault("activeRecord", false)); dataModel.put("entitySerialAnnotation", extraConfig.getOrDefault("entitySerialAnnotation", false)); dataModel.put("chainModel", extraConfig.getOrDefault("chainModel", false)); dataModel.put("entityColumnConstant", extraConfig.getOrDefault("entityColumnConstant", false)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } else { @@ -167,12 +170,12 @@ public class HibernateCodeGenerator implements CodeGenerator { dataModel.put("entityToString", false); dataModel.put("fieldUseJavaDoc", true); } - + // 确保所有模板需要的变量都存在 if (!dataModel.containsKey("entityJpaModel")) { dataModel.put("entityJpaModel", false); } - + // 添加Lombok注解 if (config.isLombok()) { List> classAnnotations = new ArrayList<>(); @@ -181,19 +184,19 @@ public class HibernateCodeGenerator implements CodeGenerator { classAnnotations.add(dataAnnotation); dataModel.put("entityClassAnnotations", classAnnotations); } - + // 添加关联字段信息 addRelationFields(dataModel, tableInfo); - + return dataModel; } - + /** * 添加关联字段信息 */ private void addRelationFields(Map dataModel, TableInfo tableInfo) { Map tableMap = (Map) dataModel.get("table"); - + // 添加一对一关联字段 List> oneToOneFields = new ArrayList<>(); Map userDetailsField = new HashMap<>(); @@ -202,7 +205,7 @@ public class HibernateCodeGenerator implements CodeGenerator { userDetailsField.put("comment", "用户详情(一对一)"); oneToOneFields.add(userDetailsField); tableMap.put("oneToOneFields", oneToOneFields); - + // 添加一对多关联字段 List> oneToManyFields = new ArrayList<>(); Map ordersField = new HashMap<>(); @@ -212,7 +215,7 @@ public class HibernateCodeGenerator implements CodeGenerator { oneToManyFields.add(ordersField); tableMap.put("oneToManyFields", oneToManyFields); } - + /** * 创建包信息映射 */ @@ -221,7 +224,7 @@ public class HibernateCodeGenerator implements CodeGenerator { packageMap.put("Entity", basePackage + ".entity"); return packageMap; } - + /** * 创建表信息映射 */ @@ -230,7 +233,7 @@ public class HibernateCodeGenerator implements CodeGenerator { tableMap.put("name", tableInfo.getTableName()); tableMap.put("comment", tableInfo.getTableComment()); tableMap.put("entityName", tableInfo.getEntityName()); - + // 字段信息 List> fields = new ArrayList<>(); List fieldNames = new ArrayList<>(); @@ -245,42 +248,42 @@ public class HibernateCodeGenerator implements CodeGenerator { fieldMap.put("capitalName", capitalize(field.getPropertyName())); fieldMap.put("annotationAttributesList", new ArrayList<>()); fields.add(fieldMap); - + // 收集字段名称 fieldNames.add(field.getColumnName()); } tableMap.put("fields", fields); - + // 添加字段名称列表(以逗号分隔) tableMap.put("fieldNames", String.join(", ", fieldNames)); - + return tableMap; } - + /** * 获取实体类框架导入包 */ private List getEntityImports(boolean useLombok) { List imports = new ArrayList<>(); - + // 添加Lombok导入 if (useLombok) { imports.add("lombok.Data"); } - + // 添加关联字段需要的导入 imports.add("java.util.List"); - + return imports; } - + /** * 获取Java导入包 */ private List getJavaImports(TableInfo tableInfo) { Set imports = new HashSet<>(); imports.add("java.io.Serializable"); - + // 根据字段类型添加相应的导入 for (FieldInfo field : tableInfo.getFields()) { if ("LocalDateTime".equals(field.getPropertyType())) { @@ -291,10 +294,10 @@ public class HibernateCodeGenerator implements CodeGenerator { imports.add("java.math.BigDecimal"); } } - + return new ArrayList<>(imports); } - + /** * 首字母大写 */ @@ -304,7 +307,7 @@ public class HibernateCodeGenerator implements CodeGenerator { } return str.substring(0, 1).toUpperCase() + str.substring(1); } - + /** * 写文件到磁盘 */ @@ -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(); } } } \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/JpaCodeGenerator.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/JpaCodeGenerator.java index 17f1bf7..001bef0 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/JpaCodeGenerator.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/JpaCodeGenerator.java @@ -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(); } } } \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisCodeGenerator.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisCodeGenerator.java index ef347ec..bd640e5 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisCodeGenerator.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisCodeGenerator.java @@ -5,27 +5,29 @@ 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.*; /** * MyBatis代码生成器 - * + * * @author yexuejc * @since 2025-01 */ +@Slf4j public class MybatisCodeGenerator implements CodeGenerator { - + @Override public GenerationMode getGenerationMode() { return GenerationMode.MYBATIS; } - + @Override public GenerationResult generate(List tableInfos, GenerationConfig config) throws Exception { List generatedFiles = new ArrayList<>(); - + for (TableInfo tableInfo : tableInfos) { // 生成Entity GeneratedFile entityFile = generateEntity(tableInfo, config); @@ -34,7 +36,7 @@ public class MybatisCodeGenerator implements CodeGenerator { // 写入文件 writeFileToDisK(entityFile, config); } - + // 生成Mapper接口 GeneratedFile mapperFile = generateMapper(tableInfo, config); if (mapperFile != null) { @@ -42,7 +44,7 @@ public class MybatisCodeGenerator implements CodeGenerator { // 写入文件 writeFileToDisK(mapperFile, config); } - + // 生成Mapper XML GeneratedFile mapperXmlFile = generateMapperXml(tableInfo, config); if (mapperXmlFile != null) { @@ -51,15 +53,15 @@ public class MybatisCodeGenerator implements CodeGenerator { writeFileToDisK(mapperXmlFile, config); } } - + return GenerationResult.success(generatedFiles); } - + @Override public List getSupportedFileTypes() { return Arrays.asList("Entity", "Mapper", "MapperXml"); } - + @Override public Map getTemplateFileMapping() { Map mapping = new HashMap<>(); @@ -68,7 +70,7 @@ public class MybatisCodeGenerator implements CodeGenerator { mapping.put("MapperXml", "mapper.xml"); return mapping; } - + @Override public Map getOutputFileMapping() { Map mapping = new HashMap<>(); @@ -77,28 +79,28 @@ public class MybatisCodeGenerator implements CodeGenerator { mapping.put("MapperXml", "{entityName}Mapper.xml"); return mapping; } - + @Override public void initialize(GenerationConfig config) throws Exception { // MyBatis生成器初始化逻辑 System.out.println("MyBatis代码生成器初始化完成"); } - + private GeneratedFile generateEntity(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + ".java"; String filePath = buildFilePath(config, "entity", fileName); - + // 获取模板引擎处理器 TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); - + // 准备数据模型 Map dataModel = buildDataModel(tableInfo, config); - + // 处理模板 String templateName = "entity.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Entity", content); } catch (Exception e) { System.err.println("生成Entity失败: " + e.getMessage()); @@ -106,22 +108,22 @@ public class MybatisCodeGenerator implements CodeGenerator { return null; } } - + private GeneratedFile generateMapper(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + "Mapper.java"; String filePath = buildFilePath(config, "mapper", fileName); - + // 获取模板引擎处理器 TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); - + // 准备数据模型 Map dataModel = buildMapperDataModel(tableInfo, config); - + // 处理模板 String templateName = "mapper.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Mapper", content); } catch (Exception e) { System.err.println("生成Mapper失败: " + e.getMessage()); @@ -129,22 +131,22 @@ public class MybatisCodeGenerator implements CodeGenerator { return null; } } - + private GeneratedFile generateMapperXml(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + "Mapper.xml"; String filePath = buildFilePath(config, "mapper", fileName); - + // 获取模板引擎处理器 TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); - + // 准备数据模型 Map dataModel = buildDataModel(tableInfo, config); - + // 处理模板 String templateName = "mapper.xml" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "MapperXml", content); } catch (Exception e) { System.err.println("生成MapperXml失败: " + e.getMessage()); @@ -152,14 +154,14 @@ public class MybatisCodeGenerator implements CodeGenerator { return null; } } - + /** * 构建文件路径,根据type配置决定路径结构 */ private String buildFilePath(GenerationConfig config, String subDir, String fileName) { String basePath = config.getOutputPath(); String type = config.getType(); - + if ("coding".equals(type)) { // coding模式:生成标准的src/main/java结构 if (fileName.endsWith(".xml")) { @@ -175,30 +177,33 @@ public class MybatisCodeGenerator implements CodeGenerator { return basePath + "/" + subDir + "/" + fileName; } } - + /** * 构建模板数据模型 */ private Map buildDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - - // 导入包 - dataModel.put("importEntityFrameworkPackages", getEntityImports(config.isLombok())); - dataModel.put("importEntityJavaPackages", getJavaImports(tableInfo)); - + + // 导入包 - 确保顺序一致 + List entityFrameworkImports = getEntityFrameworkImports(config.isLombok()); + List entityJavaImports = getEntityJavaImports(tableInfo); + + dataModel.put("importEntityFrameworkPackages", entityFrameworkImports); + dataModel.put("importEntityJavaPackages", entityJavaImports); + // Lombok配置 dataModel.put("entityLombokModel", config.isLombok()); - + // 类注解(默认为空列表) dataModel.put("entityClassAnnotations", new ArrayList<>()); - + // 实体类配置 dataModel.put("superEntityClass", null); dataModel.put("activeRecord", false); @@ -208,50 +213,50 @@ public class MybatisCodeGenerator implements CodeGenerator { dataModel.put("entityColumnConstant", false); dataModel.put("entityToString", false); dataModel.put("entityFieldUseJavaDoc", true); - + // MyBatis特定配置 dataModel.put("baseColumnList", true); // 控制是否生成Base_Column_List dataModel.put("baseResultMap", true); // 控制是否生成BaseResultMap dataModel.put("enableCache", false); // 默认不开启二级缓存 dataModel.put("cacheClassName", "org.apache.ibatis.cache.impl.PerpetualCache"); - + // Mapper配置 dataModel.put("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper"); dataModel.put("importMapperFrameworkPackages", Arrays.asList("com.baomidou.mybatisplus.core.mapper.BaseMapper")); dataModel.put("importMapperJavaPackages", new ArrayList<>()); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { // 序列化配置 dataModel.put("entitySerialVersionUID", extraConfig.getOrDefault("serialVersionUID", true)); dataModel.put("serializable", extraConfig.getOrDefault("serializable", true)); - + // toString配置 dataModel.put("entityToString", extraConfig.getOrDefault("toString", false)); - + // 字段相关配置 dataModel.put("fieldUseJavaDoc", extraConfig.getOrDefault("fieldUseJavaDoc", true)); - + // 类注解 dataModel.put("entityClassAnnotations", extraConfig.getOrDefault("entityClassAnnotations", new ArrayList<>())); - + // 实体类配置 dataModel.put("superEntityClass", extraConfig.get("superEntityClass")); dataModel.put("activeRecord", extraConfig.getOrDefault("activeRecord", false)); dataModel.put("entitySerialAnnotation", extraConfig.getOrDefault("entitySerialAnnotation", false)); dataModel.put("chainModel", extraConfig.getOrDefault("chainModel", false)); dataModel.put("entityColumnConstant", extraConfig.getOrDefault("entityColumnConstant", false)); - + // MyBatis特定配置(可覆盖默认值) dataModel.put("baseColumnList", extraConfig.getOrDefault("baseColumnList", true)); dataModel.put("baseResultMap", extraConfig.getOrDefault("baseResultMap", true)); dataModel.put("enableCache", extraConfig.getOrDefault("enableCache", false)); dataModel.put("cacheClassName", extraConfig.getOrDefault("cacheClassName", "org.apache.ibatis.cache.impl.PerpetualCache")); - + // Mapper配置 dataModel.put("superMapperClass", extraConfig.getOrDefault("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper")); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } else { @@ -260,12 +265,12 @@ public class MybatisCodeGenerator implements CodeGenerator { dataModel.put("fieldUseJavaDoc", true); dataModel.put("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper"); } - + // 确保所有模板需要的变量都存在 if (!dataModel.containsKey("entityJpaModel")) { dataModel.put("entityJpaModel", false); } - + // 添加Lombok注解 if (config.isLombok()) { List> classAnnotations = new ArrayList<>(); @@ -274,19 +279,19 @@ public class MybatisCodeGenerator implements CodeGenerator { classAnnotations.add(dataAnnotation); dataModel.put("entityClassAnnotations", classAnnotations); } - + // 添加关联字段信息 addRelationFields(dataModel, tableInfo); - + return dataModel; } - + /** * 添加关联字段信息 */ private void addRelationFields(Map dataModel, TableInfo tableInfo) { Map tableMap = (Map) dataModel.get("table"); - + // 添加一对一关联字段 List> oneToOneFields = new ArrayList<>(); Map userDetailsField = new HashMap<>(); @@ -295,7 +300,7 @@ public class MybatisCodeGenerator implements CodeGenerator { userDetailsField.put("comment", "用户详情(一对一)"); oneToOneFields.add(userDetailsField); tableMap.put("oneToOneFields", oneToOneFields); - + // 添加一对多关联字段 List> oneToManyFields = new ArrayList<>(); Map ordersField = new HashMap<>(); @@ -305,20 +310,20 @@ public class MybatisCodeGenerator implements CodeGenerator { oneToManyFields.add(ordersField); tableMap.put("oneToManyFields", oneToManyFields); } - + /** * 构建Mapper模板数据模型 */ private Map buildMapperDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // Mapper配置 dataModel.put("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper"); dataModel.put("importMapperFrameworkPackages", Arrays.asList("com.baomidou.mybatisplus.core.mapper.BaseMapper")); @@ -326,21 +331,21 @@ public class MybatisCodeGenerator implements CodeGenerator { dataModel.put("mapperAnnotationClass", null); dataModel.put("kotlin", false); dataModel.put("mapperMethodList", new ArrayList<>()); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { dataModel.put("superMapperClass", extraConfig.getOrDefault("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper")); dataModel.put("mapperAnnotationClass", extraConfig.get("mapperAnnotationClass")); dataModel.put("kotlin", extraConfig.getOrDefault("kotlin", false)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } - + return dataModel; } - + /** * 创建包信息映射 */ @@ -353,7 +358,7 @@ public class MybatisCodeGenerator implements CodeGenerator { packageMap.put("Controller", basePackage + ".controller"); return packageMap; } - + /** * 创建表信息映射 */ @@ -366,7 +371,7 @@ public class MybatisCodeGenerator implements CodeGenerator { tableMap.put("serviceName", "I" + tableInfo.getEntityName() + "Service"); tableMap.put("serviceImplName", tableInfo.getEntityName() + "ServiceImpl"); tableMap.put("controllerName", tableInfo.getEntityName() + "Controller"); - + // 字段信息 List> fields = new ArrayList<>(); List fieldNames = new ArrayList<>(); @@ -381,68 +386,69 @@ public class MybatisCodeGenerator implements CodeGenerator { fieldMap.put("capitalName", capitalize(field.getPropertyName())); fieldMap.put("annotationAttributesList", new ArrayList<>()); fields.add(fieldMap); - + // 收集字段名称 fieldNames.add(field.getColumnName()); } tableMap.put("fields", fields); - + // 添加字段名称列表(以逗号分隔) tableMap.put("fieldNames", String.join(", ", fieldNames)); - + // 添加Base_Column_List控制标志(默认为true) tableMap.put("baseColumnList", true); - + // 添加baseResultMap控制标志(默认为true) tableMap.put("baseResultMap", true); - + // 添加公共字段(这里暂时为空,可以根据需要添加) tableMap.put("commonFields", new ArrayList<>()); - + return tableMap; } - + /** - * 获取实体类框架导入包 + * 获取实体类框架导入包 - 确保顺序一致 */ - private List getEntityImports(boolean useLombok) { + private List getEntityFrameworkImports(boolean useLombok) { List imports = new ArrayList<>(); - - // 添加Lombok导入 + + // 添加Lombok导入(如果使用) if (useLombok) { imports.add("lombok.Data"); } - + + // 添加序列化导入 + imports.add("java.io.Serializable"); + // 添加关联字段需要的导入 imports.add("java.util.List"); - + return imports; } - + /** - * 获取Java导入包 + * 获取Java导入包 - 确保顺序一致 */ - private List getJavaImports(TableInfo tableInfo) { - Set imports = new HashSet<>(); - imports.add("java.io.Serializable"); - + private List getEntityJavaImports(TableInfo tableInfo) { + // 使用LinkedHashSet保持顺序并去重 + Set 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); } - + /** * 首字母大写 */ @@ -452,7 +458,7 @@ public class MybatisCodeGenerator implements CodeGenerator { } return str.substring(0, 1).toUpperCase() + str.substring(1); } - + /** * 写文件到磁盘 */ diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisPlusCodeGenerator.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisPlusCodeGenerator.java index 2956b78..2c61d7d 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisPlusCodeGenerator.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/generator/impl/MybatisPlusCodeGenerator.java @@ -5,27 +5,29 @@ 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.*; /** * MyBatis-Plus代码生成器 - * + * * @author yexuejc * @since 2025-01 */ +@Slf4j public class MybatisPlusCodeGenerator implements CodeGenerator { - + @Override public GenerationMode getGenerationMode() { return GenerationMode.MYBATIS_PLUS; } - + @Override public GenerationResult generate(List tableInfos, GenerationConfig config) throws Exception { List generatedFiles = new ArrayList<>(); - + for (TableInfo tableInfo : tableInfos) { // 生成Entity GeneratedFile entityFile = generateEntity(tableInfo, config); @@ -33,28 +35,28 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { generatedFiles.add(entityFile); writeFileToDisK(entityFile, config); } - + // 生成Mapper接口 GeneratedFile mapperFile = generateMapper(tableInfo, config); if (mapperFile != null) { generatedFiles.add(mapperFile); writeFileToDisK(mapperFile, config); } - + // 生成Service接口 GeneratedFile serviceFile = generateService(tableInfo, config); if (serviceFile != null) { generatedFiles.add(serviceFile); writeFileToDisK(serviceFile, config); } - + // 生成Service实现 GeneratedFile serviceImplFile = generateServiceImpl(tableInfo, config); if (serviceImplFile != null) { generatedFiles.add(serviceImplFile); writeFileToDisK(serviceImplFile, config); } - + // 生成Controller GeneratedFile controllerFile = generateController(tableInfo, config); if (controllerFile != null) { @@ -62,15 +64,15 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { writeFileToDisK(controllerFile, config); } } - + return GenerationResult.success(generatedFiles); } - + @Override public List getSupportedFileTypes() { return Arrays.asList("Entity", "Mapper", "Service", "ServiceImpl", "Controller"); } - + @Override public Map getTemplateFileMapping() { Map mapping = new HashMap<>(); @@ -81,7 +83,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { mapping.put("Controller", "controller.java"); return mapping; } - + @Override public Map getOutputFileMapping() { Map mapping = new HashMap<>(); @@ -92,114 +94,119 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { mapping.put("Controller", "{entityName}Controller.java"); return mapping; } - + @Override public void initialize(GenerationConfig config) throws Exception { // MyBatis-Plus生成器初始化逻辑 System.out.println("MyBatis-Plus代码生成器初始化完成"); } - + private GeneratedFile generateEntity(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + ".java"; String filePath = buildFilePath(config, "entity", fileName); - + // 获取模板引擎处理器 TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); - + // 准备数据模型 Map dataModel = buildDataModel(tableInfo, config); - + // 处理模板 String templateName = "entity.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Entity", content); } catch (Exception e) { System.err.println("生成Entity失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + private GeneratedFile generateMapper(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + "Mapper.java"; String filePath = buildFilePath(config, "mapper", fileName); - + TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); Map dataModel = buildMapperDataModel(tableInfo, config); - + String templateName = "mapper.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Mapper", content); } catch (Exception e) { System.err.println("生成Mapper失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + private GeneratedFile generateService(TableInfo tableInfo, GenerationConfig config) { try { String fileName = "I" + tableInfo.getEntityName() + "Service.java"; String filePath = buildFilePath(config, "service", fileName); - + TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); Map dataModel = buildServiceDataModel(tableInfo, config); - + String templateName = "service.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Service", content); } catch (Exception e) { System.err.println("生成Service失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + private GeneratedFile generateServiceImpl(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + "ServiceImpl.java"; String filePath = buildFilePath(config, "service/impl", fileName); - + TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); Map dataModel = buildServiceImplDataModel(tableInfo, config); - + String templateName = "serviceImpl.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "ServiceImpl", content); } catch (Exception e) { System.err.println("生成ServiceImpl失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + private GeneratedFile generateController(TableInfo tableInfo, GenerationConfig config) { try { String fileName = tableInfo.getEntityName() + "Controller.java"; String filePath = buildFilePath(config, "controller", fileName); - + TemplateEngineProcessor processor = TemplateEngineFactory.getProcessor(config.getEngine()); Map dataModel = buildControllerDataModel(tableInfo, config); - + String templateName = "controller.java" + processor.getTemplateSuffix(); String content = processor.processTemplate(templateName, dataModel); - + return new GeneratedFile(filePath, fileName, "Controller", content); } catch (Exception e) { System.err.println("生成Controller失败: " + e.getMessage()); + e.printStackTrace(); return null; } } - + /** * 构建文件路径,根据type配置决定路径结构 */ private String buildFilePath(GenerationConfig config, String subDir, String fileName) { String basePath = config.getOutputPath(); String type = config.getType(); - + if ("coding".equals(type)) { // coding模式:生成标准的src/main/java结构 String packagePath = config.getPackageName().replace(".", "/"); @@ -209,30 +216,30 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { return basePath + "/" + subDir + "/" + fileName; } } - + /** * 构建模板数据模型 */ private Map buildDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // 导入包 dataModel.put("importEntityFrameworkPackages", getEntityImports(config.isLombok())); dataModel.put("importEntityJavaPackages", getJavaImports(tableInfo)); - + // Lombok配置 dataModel.put("entityLombokModel", config.isLombok()); - + // 类注解(默认为空列表) dataModel.put("entityClassAnnotations", new ArrayList<>()); - + // 实体类配置 dataModel.put("superEntityClass", null); dataModel.put("activeRecord", false); @@ -242,30 +249,30 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("entityColumnConstant", false); dataModel.put("entityToString", false); dataModel.put("entityFieldUseJavaDoc", true); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { // 序列化配置 dataModel.put("entitySerialVersionUID", extraConfig.getOrDefault("serialVersionUID", true)); dataModel.put("serializable", extraConfig.getOrDefault("serializable", true)); - + // toString配置 dataModel.put("entityToString", extraConfig.getOrDefault("toString", false)); - + // 字段相关配置 dataModel.put("fieldUseJavaDoc", extraConfig.getOrDefault("fieldUseJavaDoc", true)); - + // 类注解 dataModel.put("entityClassAnnotations", extraConfig.getOrDefault("entityClassAnnotations", new ArrayList<>())); - + // 实体类配置 dataModel.put("superEntityClass", extraConfig.get("superEntityClass")); dataModel.put("activeRecord", extraConfig.getOrDefault("activeRecord", false)); dataModel.put("entitySerialAnnotation", extraConfig.getOrDefault("entitySerialAnnotation", false)); dataModel.put("chainModel", extraConfig.getOrDefault("chainModel", false)); dataModel.put("entityColumnConstant", extraConfig.getOrDefault("entityColumnConstant", false)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } else { @@ -275,12 +282,12 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("entityToString", false); dataModel.put("fieldUseJavaDoc", true); } - + // 确保所有模板需要的变量都存在 if (!dataModel.containsKey("entityJpaModel")) { dataModel.put("entityJpaModel", false); } - + // 添加Lombok注解 if (config.isLombok()) { List> classAnnotations = new ArrayList<>(); @@ -289,19 +296,19 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { classAnnotations.add(dataAnnotation); dataModel.put("entityClassAnnotations", classAnnotations); } - + // 添加关联字段信息 addRelationFields(dataModel, tableInfo); - + return dataModel; } - + /** * 添加关联字段信息 */ private void addRelationFields(Map dataModel, TableInfo tableInfo) { Map tableMap = (Map) dataModel.get("table"); - + // 添加一对一关联字段 List> oneToOneFields = new ArrayList<>(); Map userDetailsField = new HashMap<>(); @@ -310,7 +317,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { userDetailsField.put("comment", "用户详情(一对一)"); oneToOneFields.add(userDetailsField); tableMap.put("oneToOneFields", oneToOneFields); - + // 添加一对多关联字段 List> oneToManyFields = new ArrayList<>(); Map ordersField = new HashMap<>(); @@ -320,20 +327,20 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { oneToManyFields.add(ordersField); tableMap.put("oneToManyFields", oneToManyFields); } - + /** * 构建Mapper模板数据模型 */ private Map buildMapperDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // Mapper配置 dataModel.put("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper"); dataModel.put("importMapperFrameworkPackages", Arrays.asList("com.baomidou.mybatisplus.core.mapper.BaseMapper")); @@ -341,79 +348,79 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("mapperAnnotationClass", null); dataModel.put("kotlin", false); dataModel.put("mapperMethodList", new ArrayList<>()); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { dataModel.put("superMapperClass", extraConfig.getOrDefault("superMapperClass", "com.baomidou.mybatisplus.core.mapper.BaseMapper")); dataModel.put("mapperAnnotationClass", extraConfig.get("mapperAnnotationClass")); dataModel.put("kotlin", extraConfig.getOrDefault("kotlin", false)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } - + return dataModel; } - + /** * 构建Service模板数据模型 */ private Map buildServiceDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // Service配置 dataModel.put("superServiceClass", "com.baomidou.mybatisplus.extension.service.IService"); dataModel.put("superServiceClassPackage", "com.baomidou.mybatisplus.extension.service.IService"); dataModel.put("importServiceFrameworkPackages", Arrays.asList("com.baomidou.mybatisplus.extension.service.IService")); dataModel.put("importServiceJavaPackages", new ArrayList<>()); dataModel.put("kotlin", false); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { dataModel.put("superServiceClass", extraConfig.getOrDefault("superServiceClass", "com.baomidou.mybatisplus.extension.service.IService")); dataModel.put("superServiceClassPackage", extraConfig.getOrDefault("superServiceClassPackage", "com.baomidou.mybatisplus.extension.service.IService")); dataModel.put("kotlin", extraConfig.getOrDefault("kotlin", false)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } - + return dataModel; } - + /** * 构建ServiceImpl模板数据模型 */ private Map buildServiceImplDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // ServiceImpl配置 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); dataModel.put("generateService", true); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { @@ -421,34 +428,34 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("superServiceImplClassPackage", extraConfig.getOrDefault("superServiceImplClassPackage", "com.baomidou.mybatisplus.extension.service.impl.ServiceImpl")); dataModel.put("kotlin", extraConfig.getOrDefault("kotlin", false)); dataModel.put("generateService", extraConfig.getOrDefault("generateService", true)); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } - + return dataModel; } - + /** * 构建Controller模板数据模型 */ private Map buildControllerDataModel(TableInfo tableInfo, GenerationConfig config) { Map dataModel = new HashMap<>(); - + // 基本信息 dataModel.put("package", createPackageMap(config.getPackageName())); dataModel.put("author", config.getAuthor()); dataModel.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); dataModel.put("entity", tableInfo.getEntityName()); dataModel.put("table", createTableMap(tableInfo)); - + // Controller配置 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); @@ -456,7 +463,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("kotlin", false); dataModel.put("controllerMappingHyphen", tableInfo.getEntityName().toLowerCase().replaceAll("([a-z])([A-Z])", "$1-$2")); dataModel.put("package.ModuleName", ""); - + // 添加@Autowired注入字段 List> autowiredFields = new ArrayList<>(); Map userServiceField = new HashMap<>(); @@ -465,7 +472,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { userServiceField.put("name", "userService"); autowiredFields.add(userServiceField); dataModel.put("controllerAutowiredFields", autowiredFields); - + // 从extraConfig中获取扩展配置 Map extraConfig = config.getExtraConfig(); if (extraConfig != null) { @@ -475,14 +482,14 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { dataModel.put("controllerMappingHyphenStyle", extraConfig.getOrDefault("controllerMappingHyphenStyle", true)); dataModel.put("kotlin", extraConfig.getOrDefault("kotlin", false)); dataModel.put("package.ModuleName", extraConfig.getOrDefault("moduleName", "")); - + // 将所有extraConfig也放入dataModel,供模板使用 dataModel.putAll(extraConfig); } - + return dataModel; } - + /** * 创建包信息映射 */ @@ -495,7 +502,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { packageMap.put("Controller", basePackage + ".controller"); return packageMap; } - + /** * 创建表信息映射 */ @@ -509,7 +516,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { tableMap.put("serviceImplName", tableInfo.getEntityName() + "ServiceImpl"); tableMap.put("controllerName", tableInfo.getEntityName() + "Controller"); tableMap.put("entityPath", tableInfo.getEntityName().toLowerCase().replaceAll("([a-z])([A-Z])", "$1-$2")); - + // 字段信息 List> fields = new ArrayList<>(); List fieldNames = new ArrayList<>(); @@ -524,42 +531,42 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { fieldMap.put("capitalName", capitalize(field.getPropertyName())); fieldMap.put("annotationAttributesList", new ArrayList<>()); fields.add(fieldMap); - + // 收集字段名称 fieldNames.add(field.getColumnName()); } tableMap.put("fields", fields); - + // 添加字段名称列表(以逗号分隔) tableMap.put("fieldNames", String.join(", ", fieldNames)); - + return tableMap; } - + /** * 获取实体类框架导入包 */ private List getEntityImports(boolean useLombok) { List imports = new ArrayList<>(); - + // 添加Lombok导入 if (useLombok) { imports.add("lombok.Data"); } - + // 添加关联字段需要的导入 imports.add("java.util.List"); - + return imports; } - + /** * 获取Java导入包 */ private List getJavaImports(TableInfo tableInfo) { Set imports = new HashSet<>(); imports.add("java.io.Serializable"); - + // 根据字段类型添加相应的导入 for (FieldInfo field : tableInfo.getFields()) { if ("LocalDateTime".equals(field.getPropertyType())) { @@ -570,10 +577,10 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { imports.add("java.math.BigDecimal"); } } - + return new ArrayList<>(imports); } - + /** * 首字母大写 */ @@ -583,7 +590,7 @@ public class MybatisPlusCodeGenerator implements CodeGenerator { } return str.substring(0, 1).toUpperCase() + str.substring(1); } - + /** * 写文件到磁盘 */ @@ -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(); } } } \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/template/impl/FreemarkerTemplateProcessor.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/template/impl/FreemarkerTemplateProcessor.java index 2c491e9..8e347d4 100644 --- a/db2java-core/src/main/java/com/yexuejc/db2java/core/template/impl/FreemarkerTemplateProcessor.java +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/template/impl/FreemarkerTemplateProcessor.java @@ -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 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 dataModel) throws Exception { - // 调试输出 - System.out.println("模板路径: " + templatePath); - // 直接根据模板路径判断生成类型,避免模板内容解析错误 - return generateFallbackContent(templatePath, dataModel); + public String processTemplate(String templateName, Map 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; - } - - /** - * 读取模板文件 - */ - private String readTemplateFile(String templatePath) { + // 确保configuration已初始化 + if (configuration == null) { + try { + initialize(null); + } catch (Exception e) { + System.err.println("初始化Freemarker配置失败: " + e.getMessage()); + return false; + } + } + 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 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(" 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 dataModel) { StringBuilder code = new StringBuilder(); - // 获取数据 @SuppressWarnings("unchecked") Map packageMap = (Map) dataModel.get("package"); - @SuppressWarnings("unchecked") - Map tableMap = (Map) 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 tableMap = (Map) 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 importEntityFrameworkPackages = (List) dataModel.get("importEntityFrameworkPackages"); + @SuppressWarnings("unchecked") + List importEntityJavaPackages = (List) 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> entityClassAnnotations = (List>) dataModel.get("entityClassAnnotations"); + if (entityClassAnnotations != null) { + for (Map 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 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 dataModel) { - StringBuilder code = new StringBuilder(); - - @SuppressWarnings("unchecked") - Map packageMap = (Map) dataModel.get("package"); - @SuppressWarnings("unchecked") - Map tableMap = (Map) 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(" * \n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 前端控制器\n"); - } - code.append(" * \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 dataModel) { - StringBuilder code = new StringBuilder(); - - @SuppressWarnings("unchecked") - Map packageMap = (Map) dataModel.get("package"); - @SuppressWarnings("unchecked") - Map tableMap = (Map) 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(" * \n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 服务类\n"); - } - code.append(" * \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 dataModel) { - StringBuilder code = new StringBuilder(); - - @SuppressWarnings("unchecked") - Map packageMap = (Map) dataModel.get("package"); - @SuppressWarnings("unchecked") - Map tableMap = (Map) 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(" * \n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 服务实现类\n"); - } - code.append(" * \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 dataModel) { + private String generateMapperJavaCode(Map dataModel) { StringBuilder code = new StringBuilder(); @SuppressWarnings("unchecked") Map packageMap = (Map) dataModel.get("package"); - @SuppressWarnings("unchecked") - Map tableMap = (Map) dataModel.get("table"); String entity = safeString(dataModel.get("entity")); String author = safeString(dataModel.get("author")); String date = safeString(dataModel.get("date")); + @SuppressWarnings("unchecked") + Map tableMap = (Map) 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 dataModel) { + StringBuilder code = new StringBuilder(); + code.append("// 默认生成的代码\n"); + code.append("// 请检查模板文件是否存在\n"); + return code.toString(); + } + /** * 获取JDBC类型 */ diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/DatabaseUtils.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/DatabaseUtils.java new file mode 100644 index 0000000..5668519 --- /dev/null +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/DatabaseUtils.java @@ -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 getTableInfos(Connection connection, GenerationConfig config) throws SQLException { + List 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 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 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类 +} \ No newline at end of file diff --git a/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/TypeMappingConfig.java b/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/TypeMappingConfig.java new file mode 100644 index 0000000..ee6feaa --- /dev/null +++ b/db2java-core/src/main/java/com/yexuejc/db2java/core/utils/TypeMappingConfig.java @@ -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 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 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 getAllTypeMappings() { + return new HashMap<>(TYPE_MAPPING); + } +} \ No newline at end of file diff --git a/db2java-core/src/main/resources/templates/entity.java.btl b/db2java-core/src/main/resources/templates/entity.java.btl index dc79114..dae4c62 100644 --- a/db2java-core/src/main/resources/templates/entity.java.btl +++ b/db2java-core/src/main/resources/templates/entity.java.btl @@ -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){ %> diff --git a/db2java-core/src/main/resources/templates/entity.java.ftl b/db2java-core/src/main/resources/templates/entity.java.ftl index aa09ff1..6ff181a 100644 --- a/db2java-core/src/main/resources/templates/entity.java.ftl +++ b/db2java-core/src/main/resources/templates/entity.java.ftl @@ -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"> @@ -110,4 +146,4 @@ public class ${entity} { "}"; } #if> -} +} \ No newline at end of file diff --git a/db2java-core/src/main/resources/templates/entity.java.vm b/db2java-core/src/main/resources/templates/entity.java.vm index 2b1d69e..4599952 100644 --- a/db2java-core/src/main/resources/templates/entity.java.vm +++ b/db2java-core/src/main/resources/templates/entity.java.vm @@ -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 一对多关联字段 ---------- diff --git a/db2java-core/src/test/java/com/yexuejc/db2java/core/MysqlDb2JavaCoreTest.java b/db2java-core/src/test/java/com/yexuejc/db2java/core/MysqlDb2JavaCoreTest.java new file mode 100644 index 0000000..88777b7 --- /dev/null +++ b/db2java-core/src/test/java/com/yexuejc/db2java/core/MysqlDb2JavaCoreTest.java @@ -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); + } +} diff --git a/db2java-core/src/test/java/example/Db2JavaExample.java b/db2java-core/src/test/java/example/Db2JavaExample.java index 4d2adb2..6e65fb6 100644 --- a/db2java-core/src/test/java/example/Db2JavaExample.java +++ b/db2java-core/src/test/java/example/Db2JavaExample.java @@ -20,7 +20,7 @@ public class Db2JavaExample { public static void main(String[] args) { try { System.out.println("=== 改进的DB2Java代码生成测试 ==="); - + // 模拟一个表信息 TableInfo userTable = createUserTable(); List tableInfos = Arrays.asList(userTable); @@ -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()); diff --git a/db2java-web/pom.xml b/db2java-web/pom.xml index 42b1567..a311462 100644 --- a/db2java-web/pom.xml +++ b/db2java-web/pom.xml @@ -2,116 +2,83 @@ 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + top.yexuejc db2java-web 1.0-SNAPSHOT + db2java-web + Web interface for db2java code generation tool - 3.14.0 - 24 + 17 UTF-8 UTF-8 - quarkus-bom - io.quarkus.platform - 3.26.3 - true - 3.5.3 - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - + - io.quarkus - quarkus-arc + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.springframework.boot + spring-boot-starter-test + test - io.quarkus - quarkus-junit5 - test + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + top.yexuejc + db2java-core + 1.0-SNAPSHOT - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - native-image-agent - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - true - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - - - ${project.build.directory}/${project.build.finalName}-runner - - org.jboss.logmanager.LogManager - ${maven.home} - - + org.springframework.boot + spring-boot-maven-plugin - - - - native - - - native - - - - false - true - - - - + \ No newline at end of file diff --git a/db2java-web/src/main/java/com/yexuejc/db2java/web/Application.java b/db2java-web/src/main/java/com/yexuejc/db2java/web/Application.java new file mode 100644 index 0000000..0a6063f --- /dev/null +++ b/db2java-web/src/main/java/com/yexuejc/db2java/web/Application.java @@ -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); + } +} \ No newline at end of file diff --git a/db2java-web/src/main/java/com/yexuejc/db2java/web/config/DataSourceProperties.java b/db2java-web/src/main/java/com/yexuejc/db2java/web/config/DataSourceProperties.java new file mode 100644 index 0000000..4972249 --- /dev/null +++ b/db2java-web/src/main/java/com/yexuejc/db2java/web/config/DataSourceProperties.java @@ -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; + } +} \ No newline at end of file diff --git a/db2java-web/src/main/java/com/yexuejc/db2java/web/config/GenerateProperties.java b/db2java-web/src/main/java/com/yexuejc/db2java/web/config/GenerateProperties.java new file mode 100644 index 0000000..b1c0be7 --- /dev/null +++ b/db2java-web/src/main/java/com/yexuejc/db2java/web/config/GenerateProperties.java @@ -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 ignoreTable; + private List ignoreColumn; + private List 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 getIgnoreTable() { + return ignoreTable; + } + + public void setIgnoreTable(List ignoreTable) { + this.ignoreTable = ignoreTable; + } + + public List getIgnoreColumn() { + return ignoreColumn; + } + + public void setIgnoreColumn(List ignoreColumn) { + this.ignoreColumn = ignoreColumn; + } + + public List getIncludeTable() { + return includeTable; + } + + public void setIncludeTable(List 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; + } +} \ No newline at end of file diff --git a/db2java-web/src/main/java/com/yexuejc/db2java/web/controller/CodeGeneratorController.java b/db2java-web/src/main/java/com/yexuejc/db2java/web/controller/CodeGeneratorController.java new file mode 100644 index 0000000..bfceeb7 --- /dev/null +++ b/db2java-web/src/main/java/com/yexuejc/db2java/web/controller/CodeGeneratorController.java @@ -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 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 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 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 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:/"; + } +} \ No newline at end of file diff --git a/db2java-web/src/main/resources/application.yml b/db2java-web/src/main/resources/application.yml new file mode 100644 index 0000000..de6b8e4 --- /dev/null +++ b/db2java-web/src/main/resources/application.yml @@ -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) + ## @RequestMapping("/managerUserActionHistory") -> @RequestMapping("/manager-user-action-history") + mappingHyphen: true + # 生成 @RestController 控制器(默认 false) + ## @Controller -> @RestController + restStyle: true + # 自定义继承的Controller类全称,带包名,默认为空 + ## superClass: com.yexuejc.db2java.export.controller.BaseController + superClass: + diff --git a/db2java-web/src/main/resources/templates/index.html b/db2java-web/src/main/resources/templates/index.html new file mode 100644 index 0000000..e2af2ca --- /dev/null +++ b/db2java-web/src/main/resources/templates/index.html @@ -0,0 +1,179 @@ + + + + + + DB2Java代码生成器 + + + + + DB2Java代码生成器 + + + + + + + + + + + + + + + + 数据库配置 + + + + + 数据库URL + + + + 驱动类名 + + + + + + 用户名 + + + + 密码 + + + + + + + + + 生成配置 + + + + + 生成模式 + + + Hibernate + + JPA + MyBatis + + + MyBatis-Plus + + + + + 生成代码模式 + + File + Coding + + + + + + + 输出目录 + + + + 包名 + + + + + + + 作者 + + + + 模板引擎 + + + FreeMarker + + Velocity + + Beetl + Enjoy + + + + + + + + + 启用Lombok + + + + + + 合并模式 + + + + + + 覆盖文件 + + + + + + + + + 表和字段配置 + + + + 包含表(每行一个) + + + + + + 忽略表(每行一个) + + + + + 忽略字段(每行一个) + + + + + + + 生成代码 + + + + + + + \ No newline at end of file diff --git a/问题修改一览.csv b/问题修改一览.csv new file mode 100644 index 0000000..05b49a8 --- /dev/null +++ b/问题修改一览.csv @@ -0,0 +1,7 @@ +问题点,对应方案,类似问题是否对应 +HTML表单请求参数与接口定义不匹配导致400错误,将Controller中List参数类型改为String,并在代码中进行分割处理,是 +可选复选框参数缺失导致400错误,为lombok、merge、override参数添加@RequestParam(defaultValue = "false")注解,是 +换行符处理不一致,将字符串分割逻辑从"\\r?\\n"修改为"[\\r\\n]+"正则表达式,是 +字段命名策略未生效,在DatabaseUtils中正确获取和使用fieldNaming配置,是 +模板处理器接口实现不完整,添加templateExists方法实现并修复导入语句,是 +数据库字段和Java属性类型映射不正确,创建TypeMappingConfig配置类进行类型映射,是 \ No newline at end of file diff --git a/问题修改一览.txt b/问题修改一览.txt new file mode 100644 index 0000000..8df7834 --- /dev/null +++ b/问题修改一览.txt @@ -0,0 +1,8 @@ +问题点,对应案,类似问题是否对应 +1. HTML表单参数与Controller接口参数类型不匹配导致400错误,修改Controller中ignoreTable、ignoreColumn、includeTable参数类型从List为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确保类名和文件名一致,是 \ No newline at end of file
\n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 前端控制器\n"); - } - code.append(" *
\n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 服务类\n"); - } - code.append(" *
\n"); - if (tableMap != null && tableMap.get("comment") != null) { - code.append(" * ").append(tableMap.get("comment")).append(" 服务实现类\n"); - } - code.append(" *
@RequestMapping("/managerUserActionHistory")
@RequestMapping("/manager-user-action-history")
@RestController
@Controller