Browse Source

引入 Velocity 模板引擎,生成代码~

YunaiV 4 years ago
parent
commit
1bea2ea7f8

+ 7 - 0
pom.xml

@@ -54,6 +54,7 @@
         <mapstruct.version>1.4.1.Final</mapstruct.version>
         <mapstruct.version>1.4.1.Final</mapstruct.version>
         <hutool.version>5.5.6</hutool.version>
         <hutool.version>5.5.6</hutool.version>
         <easyexcel.verion>2.2.7</easyexcel.verion>
         <easyexcel.verion>2.2.7</easyexcel.verion>
+        <velocity.version>2.2</velocity.version>
     </properties>
     </properties>
 
 
     <!-- 依赖声明 -->
     <!-- 依赖声明 -->
@@ -221,6 +222,12 @@
             <version>${easyexcel.verion}</version>
             <version>${easyexcel.verion}</version>
         </dependency>
         </dependency>
 
 
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <version>${velocity.version}</version>
+        </dependency>
+
     </dependencies>
     </dependencies>
 
 
 
 

+ 5 - 2
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictTypeDO.java

@@ -5,8 +5,7 @@ import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
+import lombok.*;
 
 
 /**
 /**
  * 字典类型表
  * 字典类型表
@@ -16,6 +15,10 @@ import lombok.EqualsAndHashCode;
 @TableName("sys_dict_type")
 @TableName("sys_dict_type")
 @Data
 @Data
 @EqualsAndHashCode(callSuper = true)
 @EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class SysDictTypeDO extends BaseDO {
 public class SysDictTypeDO extends BaseDO {
 
 
     /**
     /**

+ 10 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dao/coegen/ToolCodegenColumnMapper.java

@@ -2,8 +2,18 @@ package cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen;
 
 
 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
 import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;
 
 
+import java.util.List;
+
 @Mapper
 @Mapper
 public interface ToolCodegenColumnMapper extends BaseMapperX<ToolCodegenColumnDO> {
 public interface ToolCodegenColumnMapper extends BaseMapperX<ToolCodegenColumnDO> {
+
+    default List<ToolCodegenColumnDO> selectByTableId(Long tableId) {
+        return selectList(new QueryWrapper<ToolCodegenColumnDO>()
+                .eq("table_id", tableId)
+                .orderByAsc("ordinal_position"));
+    }
+
 }
 }

+ 6 - 3
src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dataobject/codegen/ToolCodegenColumnDO.java

@@ -95,16 +95,19 @@ public class ToolCodegenColumnDO extends BaseDO {
      */
      */
     private Boolean updateOperation;
     private Boolean updateOperation;
     /**
     /**
-     * 是否为 List 查询操作的返回字段
+     * 是否为 List 查询操作的字段
      */
      */
-    private Boolean listOperationResult;
+    private Boolean listOperation;
     /**
     /**
      * List 查询操作的条件类型
      * List 查询操作的条件类型
-     * 如果为空,则说明不是查询字段
      *
      *
      * 枚举 {@link ToolCodegenColumnListConditionEnum}
      * 枚举 {@link ToolCodegenColumnListConditionEnum}
      */
      */
     private String listOperationCondition;
     private String listOperationCondition;
+    /**
+     * 是否为 List 查询操作的返回字段
+     */
+    private Boolean listOperationResult;
 
 
     // ========== UI 相关字段 ==========
     // ========== UI 相关字段 ==========
 
 

+ 44 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java

@@ -0,0 +1,44 @@
+package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
+
+import cn.hutool.extra.template.TemplateConfig;
+import cn.hutool.extra.template.TemplateEngine;
+import cn.hutool.extra.template.TemplateUtil;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 代码生成的引擎,用于具体生成代码
+ * 目前基于 {@link org.apache.velocity.app.Velocity} 模板引擎实现
+ *
+ * 考虑到 Java 模板引擎的框架非常多,Freemarker、Velocity、Thymeleaf 等等,所以我们采用 hutool 封装的 {@link cn.hutool.extra.template.Template} 抽象
+ *
+ * @author 芋道源码
+ */
+@Component
+public class ToolCodegenEngine {
+
+    /**
+     * 模板引擎,由 hutool 实现
+     */
+    private final TemplateEngine templateEngine;
+
+    public ToolCodegenEngine() {
+        TemplateConfig config = new TemplateConfig();
+        config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH);
+        this.templateEngine = TemplateUtil.createEngine(config);
+    }
+
+    public void execute(ToolCodegenTableDO table, List<ToolCodegenColumnDO> columns) {
+        Map<String, Object> bindingMap = new HashMap<>();
+        bindingMap.put("table", table);
+        bindingMap.put("columns", columns);
+        String result = templateEngine.getTemplate("codegen/dal/do.vm").render(bindingMap);
+        System.out.println(result);
+    }
+
+}

+ 31 - 33
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java

@@ -5,16 +5,9 @@ import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.dashboard.modules.tool.convert.codegen.CodegenConvert;
 import cn.iocoder.dashboard.modules.tool.convert.codegen.CodegenConvert;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenColumnMapper;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenTableMapper;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaColumnMapper;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaTableMapper;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaColumnDO;
-import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaTableDO;
-import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnHtmlTypeEnum;
-import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnListConditionEnum;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.*;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.*;
+import cn.iocoder.dashboard.modules.tool.enums.codegen.*;
 import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
 import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Sets;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
@@ -60,8 +53,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     /**
     /**
      * 新增操作,不需要传递的字段
      * 新增操作,不需要传递的字段
      */
      */
-    private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet(
-            "id");
+    private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
     /**
     /**
      * 修改操作,不需要传递的字段
      * 修改操作,不需要传递的字段
      */
      */
@@ -69,11 +61,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
     /**
     /**
      * 列表操作的条件,不需要传递的字段
      * 列表操作的条件,不需要传递的字段
      */
      */
-    private static final Set<String> LIST_OPERATION_CONDITION_COLUMN = Sets.newHashSet();
+    private static final Set<String> LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
     /**
     /**
      * 列表操作的结果,不需要返回的字段
      * 列表操作的结果,不需要返回的字段
      */
      */
-    private static final Set<String> LIST_OPERATION_RESULT_COLUMN = Sets.newHashSet();
+    private static final Set<String> LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet();
 
 
     /**
     /**
      * Java 类型与 MySQL 类型的映射关系
      * Java 类型与 MySQL 类型的映射关系
@@ -90,13 +82,15 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
             .build();
             .build();
 
 
     static {
     static {
+        // 处理 OPERATION 相关的字段
         Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> {
         Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> {
             CREATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
             CREATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
             UPDATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
             UPDATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
-            LIST_OPERATION_CONDITION_COLUMN.add(field.getName());
-            LIST_OPERATION_RESULT_COLUMN.add(field.getName());
+            LIST_OPERATION_EXCLUDE_COLUMN.add(field.getName());
+            LIST_OPERATION_RESULT_EXCLUDE_COLUMN.add(field.getName());
         });
         });
-        LIST_OPERATION_RESULT_COLUMN.remove("create_time"); // 创建时间,还是需要返回的
+        LIST_OPERATION_EXCLUDE_COLUMN.remove("create_time"); // 创建时间,还是可能需要传递的
+        LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("create_time"); // 创建时间,还是需要返回的
     }
     }
 
 
     @Resource
     @Resource
@@ -134,7 +128,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         columns.forEach(column -> {
         columns.forEach(column -> {
             initColumnDefault(column);
             initColumnDefault(column);
             column.setTableId(table.getId());
             column.setTableId(table.getId());
-            codegenColumnMapper.insert(column);
+            codegenColumnMapper.insert(column); // TODO 批量插入
         });
         });
         return table.getId();
         return table.getId();
     }
     }
@@ -150,10 +144,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         table.setBusinessName(StrUtil.subAfter(table.getTableName(),
         table.setBusinessName(StrUtil.subAfter(table.getTableName(),
                 '_', false)); // 第一个 _ 前缀的后面,作为 module 名字
                 '_', false)); // 第一个 _ 前缀的后面,作为 module 名字
         table.setBusinessName(StrUtil.toCamelCase(table.getBusinessName())); // 可能存在多个 _ 的情况,转换成驼峰
         table.setBusinessName(StrUtil.toCamelCase(table.getBusinessName())); // 可能存在多个 _ 的情况,转换成驼峰
-        table.setClassName(StrUtil.toCamelCase(table.getClassName())); // 驼峰
-        table.setClassComment(StrUtil.subBefore(table.getClassComment(), // 去除结尾的表,作为类描述
+        table.setClassName(StrUtil.upperFirst(StrUtil.toCamelCase(table.getTableName()))); // 驼峰 + 首字母大写
+        table.setClassComment(StrUtil.subBefore(table.getTableComment(), // 去除结尾的表,作为类描述
                 '表', true));
                 '表', true));
         table.setAuthor("芋艿"); // TODO 稍后改成创建人
         table.setAuthor("芋艿"); // TODO 稍后改成创建人
+        table.setTemplateType(ToolCodegenTemplateTypeEnum.CRUD.getType());
     }
     }
 
 
     /**
     /**
@@ -175,7 +170,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         column.setJavaField(StrUtil.toCamelCase(column.getColumnName()));
         column.setJavaField(StrUtil.toCamelCase(column.getColumnName()));
         // 处理 dictType 字段,暂无
         // 处理 dictType 字段,暂无
         // 处理 javaType 字段
         // 处理 javaType 字段
-        String dbType = StrUtil.subBefore(column.getColumnName(), ')', false);
+        String dbType = StrUtil.subBefore(column.getColumnType(), '(', false);
         javaTypeMappings.entrySet().stream()
         javaTypeMappings.entrySet().stream()
                 .filter(entry -> entry.getValue().contains(dbType))
                 .filter(entry -> entry.getValue().contains(dbType))
                 .findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
                 .findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
@@ -187,26 +182,29 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
 
 
     private void processColumnOperation(ToolCodegenColumnDO column) {
     private void processColumnOperation(ToolCodegenColumnDO column) {
         // 处理 createOperation 字段
         // 处理 createOperation 字段
-        column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName())
-            && !column.getPrimaryKey()); // 非主键
+        column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
+            && !column.getPrimaryKey()); // 对于主键,创建时无需传递
         // 处理 updateOperation 字段
         // 处理 updateOperation 字段
-        column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName()));
-        // 处理 listOperationResult 字段
-        column.setListOperationResult(!LIST_OPERATION_RESULT_COLUMN.contains(column.getColumnName()));
-        // 处理 listOperationCondition 字段。默认设置为需要过滤的条件,手动进行取消
-        if (!LIST_OPERATION_CONDITION_COLUMN.contains(column.getColumnName())
-            && !column.getPrimaryKey()) { // 非主键
-            column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition());
-        }
+        column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
+            || column.getPrimaryKey()); // 对于主键,更新时需要传递
+        // 处理 listOperation 字段
+        column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
+                && !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递
+        // 处理 listOperationCondition 字段
         columnListOperationConditionMappings.entrySet().stream()
         columnListOperationConditionMappings.entrySet().stream()
-                .filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
+                .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
                 .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
                 .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
+        if (column.getListOperationCondition() == null) {
+            column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition());
+        }
+        // 处理 listOperationResult 字段
+        column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField()));
     }
     }
 
 
     private void processColumnUI(ToolCodegenColumnDO column) {
     private void processColumnUI(ToolCodegenColumnDO column) {
         // 基于后缀进行匹配
         // 基于后缀进行匹配
         columnHtmlTypeMappings.entrySet().stream()
         columnHtmlTypeMappings.entrySet().stream()
-                .filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
+                .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
                 .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
                 .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
         // 如果是 Boolean 类型时,设置为 radio 类型.
         // 如果是 Boolean 类型时,设置为 radio 类型.
         // 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.
         // 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.

+ 30 - 0
src/main/resources/codegen/dal/do.vm

@@ -0,0 +1,30 @@
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.*;
+import java.util.*;
+
+/**
+* ${table.description}
+*/
+@TableName("${table.tableName}")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ${table.tableName}DO extends BaseDO {
+
+#foreach ($column in $columns)
+    /**
+    * ${column.columnComment}
+    */
+#if(${column.primaryKey} && ${column.javaType} != 'String')
+    @TableId
+#end
+#if(${column.primaryKey} && ${column.javaType} == 'String')
+    @TableId(type = IdType.INPUT)
+#end
+    private ${column.javaType} ${column.javaField};
+#end
+
+}

+ 32 - 0
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngineTest.java

@@ -0,0 +1,32 @@
+package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
+
+import cn.iocoder.dashboard.TestApplication;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenColumnMapper;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenTableMapper;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
+import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class ToolCodegenEngineTest {
+
+    @Resource
+    private ToolCodegenTableMapper codegenTableMapper;
+    @Resource
+    private ToolCodegenColumnMapper codegenColumnMapper;
+
+    @Resource
+    private ToolCodegenEngine codegenEngine;
+
+    @Test
+    public void testExecute() {
+        ToolCodegenTableDO table = codegenTableMapper.selectById(8);
+        List<ToolCodegenColumnDO> columns = codegenColumnMapper.selectByTableId(table.getId());
+        codegenEngine.execute(table, columns);
+    }
+
+}

+ 22 - 0
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImplTest.java

@@ -0,0 +1,22 @@
+package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
+
+import cn.iocoder.dashboard.TestApplication;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class ToolCodegenServiceImplTest {
+
+    @Resource
+    private ToolCodegenServiceImpl toolCodegenService;
+
+    @Test
+    public void tetCreateCodegenTable() {
+        toolCodegenService.createCodegenTable("sys_dict_type");
+    }
+
+}