Commit 1bea2ea7f8034863a8f994e006df01070865760e

Authored by YunaiV
1 parent 0be7138e

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

... ... @@ -54,6 +54,7 @@
54 54 <mapstruct.version>1.4.1.Final</mapstruct.version>
55 55 <hutool.version>5.5.6</hutool.version>
56 56 <easyexcel.verion>2.2.7</easyexcel.verion>
  57 + <velocity.version>2.2</velocity.version>
57 58 </properties>
58 59  
59 60 <!-- 依赖声明 -->
... ... @@ -221,6 +222,12 @@
221 222 <version>${easyexcel.verion}</version>
222 223 </dependency>
223 224  
  225 + <dependency>
  226 + <groupId>org.apache.velocity</groupId>
  227 + <artifactId>velocity-engine-core</artifactId>
  228 + <version>${velocity.version}</version>
  229 + </dependency>
  230 +
224 231 </dependencies>
225 232  
226 233  
... ...
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;
5 5 import com.baomidou.mybatisplus.annotation.TableField;
6 6 import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
8   -import lombok.Data;
9   -import lombok.EqualsAndHashCode;
  8 +import lombok.*;
10 9  
11 10 /**
12 11 * 字典类型表
... ... @@ -16,6 +15,10 @@ import lombok.EqualsAndHashCode;
16 15 @TableName("sys_dict_type")
17 16 @Data
18 17 @EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
19 22 public class SysDictTypeDO extends BaseDO {
20 23  
21 24 /**
... ...
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;
2 2  
3 3 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
  5 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 6 import org.apache.ibatis.annotations.Mapper;
6 7  
  8 +import java.util.List;
  9 +
7 10 @Mapper
8 11 public interface ToolCodegenColumnMapper extends BaseMapperX<ToolCodegenColumnDO> {
  12 +
  13 + default List<ToolCodegenColumnDO> selectByTableId(Long tableId) {
  14 + return selectList(new QueryWrapper<ToolCodegenColumnDO>()
  15 + .eq("table_id", tableId)
  16 + .orderByAsc("ordinal_position"));
  17 + }
  18 +
9 19 }
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dataobject/codegen/ToolCodegenColumnDO.java
... ... @@ -95,16 +95,19 @@ public class ToolCodegenColumnDO extends BaseDO {
95 95 */
96 96 private Boolean updateOperation;
97 97 /**
98   - * 是否为 List 查询操作的返回字段
  98 + * 是否为 List 查询操作的字段
99 99 */
100   - private Boolean listOperationResult;
  100 + private Boolean listOperation;
101 101 /**
102 102 * List 查询操作的条件类型
103   - * 如果为空,则说明不是查询字段
104 103 *
105 104 * 枚举 {@link ToolCodegenColumnListConditionEnum}
106 105 */
107 106 private String listOperationCondition;
  107 + /**
  108 + * 是否为 List 查询操作的返回字段
  109 + */
  110 + private Boolean listOperationResult;
108 111  
109 112 // ========== UI 相关字段 ==========
110 113  
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
  2 +
  3 +import cn.hutool.extra.template.TemplateConfig;
  4 +import cn.hutool.extra.template.TemplateEngine;
  5 +import cn.hutool.extra.template.TemplateUtil;
  6 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
  7 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +import java.util.HashMap;
  11 +import java.util.List;
  12 +import java.util.Map;
  13 +
  14 +/**
  15 + * 代码生成的引擎,用于具体生成代码
  16 + * 目前基于 {@link org.apache.velocity.app.Velocity} 模板引擎实现
  17 + *
  18 + * 考虑到 Java 模板引擎的框架非常多,Freemarker、Velocity、Thymeleaf 等等,所以我们采用 hutool 封装的 {@link cn.hutool.extra.template.Template} 抽象
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@Component
  23 +public class ToolCodegenEngine {
  24 +
  25 + /**
  26 + * 模板引擎,由 hutool 实现
  27 + */
  28 + private final TemplateEngine templateEngine;
  29 +
  30 + public ToolCodegenEngine() {
  31 + TemplateConfig config = new TemplateConfig();
  32 + config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH);
  33 + this.templateEngine = TemplateUtil.createEngine(config);
  34 + }
  35 +
  36 + public void execute(ToolCodegenTableDO table, List<ToolCodegenColumnDO> columns) {
  37 + Map<String, Object> bindingMap = new HashMap<>();
  38 + bindingMap.put("table", table);
  39 + bindingMap.put("columns", columns);
  40 + String result = templateEngine.getTemplate("codegen/dal/do.vm").render(bindingMap);
  41 + System.out.println(result);
  42 + }
  43 +
  44 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java
... ... @@ -5,16 +5,9 @@ import cn.hutool.core.map.MapUtil;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
7 7 import cn.iocoder.dashboard.modules.tool.convert.codegen.CodegenConvert;
8   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenColumnMapper;
9   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenTableMapper;
10   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaColumnMapper;
11   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolInformationSchemaTableMapper;
12   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
13   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
14   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaColumnDO;
15   -import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolInformationSchemaTableDO;
16   -import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnHtmlTypeEnum;
17   -import cn.iocoder.dashboard.modules.tool.enums.codegen.ToolCodegenColumnListConditionEnum;
  8 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.*;
  9 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.*;
  10 +import cn.iocoder.dashboard.modules.tool.enums.codegen.*;
18 11 import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
19 12 import com.google.common.collect.Sets;
20 13 import org.springframework.stereotype.Service;
... ... @@ -60,8 +53,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
60 53 /**
61 54 * 新增操作,不需要传递的字段
62 55 */
63   - private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet(
64   - "id");
  56 + private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
65 57 /**
66 58 * 修改操作,不需要传递的字段
67 59 */
... ... @@ -69,11 +61,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
69 61 /**
70 62 * 列表操作的条件,不需要传递的字段
71 63 */
72   - private static final Set<String> LIST_OPERATION_CONDITION_COLUMN = Sets.newHashSet();
  64 + private static final Set<String> LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
73 65 /**
74 66 * 列表操作的结果,不需要返回的字段
75 67 */
76   - private static final Set<String> LIST_OPERATION_RESULT_COLUMN = Sets.newHashSet();
  68 + private static final Set<String> LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet();
77 69  
78 70 /**
79 71 * Java 类型与 MySQL 类型的映射关系
... ... @@ -90,13 +82,15 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
90 82 .build();
91 83  
92 84 static {
  85 + // 处理 OPERATION 相关的字段
93 86 Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> {
94 87 CREATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
95 88 UPDATE_OPERATION_EXCLUDE_COLUMN.add(field.getName());
96   - LIST_OPERATION_CONDITION_COLUMN.add(field.getName());
97   - LIST_OPERATION_RESULT_COLUMN.add(field.getName());
  89 + LIST_OPERATION_EXCLUDE_COLUMN.add(field.getName());
  90 + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.add(field.getName());
98 91 });
99   - LIST_OPERATION_RESULT_COLUMN.remove("create_time"); // 创建时间,还是需要返回的
  92 + LIST_OPERATION_EXCLUDE_COLUMN.remove("create_time"); // 创建时间,还是可能需要传递的
  93 + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("create_time"); // 创建时间,还是需要返回的
100 94 }
101 95  
102 96 @Resource
... ... @@ -134,7 +128,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
134 128 columns.forEach(column -> {
135 129 initColumnDefault(column);
136 130 column.setTableId(table.getId());
137   - codegenColumnMapper.insert(column);
  131 + codegenColumnMapper.insert(column); // TODO 批量插入
138 132 });
139 133 return table.getId();
140 134 }
... ... @@ -150,10 +144,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
150 144 table.setBusinessName(StrUtil.subAfter(table.getTableName(),
151 145 '_', false)); // 第一个 _ 前缀的后面,作为 module 名字
152 146 table.setBusinessName(StrUtil.toCamelCase(table.getBusinessName())); // 可能存在多个 _ 的情况,转换成驼峰
153   - table.setClassName(StrUtil.toCamelCase(table.getClassName())); // 驼峰
154   - table.setClassComment(StrUtil.subBefore(table.getClassComment(), // 去除结尾的表,作为类描述
  147 + table.setClassName(StrUtil.upperFirst(StrUtil.toCamelCase(table.getTableName()))); // 驼峰 + 首字母大写
  148 + table.setClassComment(StrUtil.subBefore(table.getTableComment(), // 去除结尾的表,作为类描述
155 149 '表', true));
156 150 table.setAuthor("芋艿"); // TODO 稍后改成创建人
  151 + table.setTemplateType(ToolCodegenTemplateTypeEnum.CRUD.getType());
157 152 }
158 153  
159 154 /**
... ... @@ -175,7 +170,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
175 170 column.setJavaField(StrUtil.toCamelCase(column.getColumnName()));
176 171 // 处理 dictType 字段,暂无
177 172 // 处理 javaType 字段
178   - String dbType = StrUtil.subBefore(column.getColumnName(), ')', false);
  173 + String dbType = StrUtil.subBefore(column.getColumnType(), '(', false);
179 174 javaTypeMappings.entrySet().stream()
180 175 .filter(entry -> entry.getValue().contains(dbType))
181 176 .findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
... ... @@ -187,26 +182,29 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
187 182  
188 183 private void processColumnOperation(ToolCodegenColumnDO column) {
189 184 // 处理 createOperation 字段
190   - column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName())
191   - && !column.getPrimaryKey()); // 非主键
  185 + column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
  186 + && !column.getPrimaryKey()); // 对于主键,创建时无需传递
192 187 // 处理 updateOperation 字段
193   - column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName()));
194   - // 处理 listOperationResult 字段
195   - column.setListOperationResult(!LIST_OPERATION_RESULT_COLUMN.contains(column.getColumnName()));
196   - // 处理 listOperationCondition 字段。默认设置为需要过滤的条件,手动进行取消
197   - if (!LIST_OPERATION_CONDITION_COLUMN.contains(column.getColumnName())
198   - && !column.getPrimaryKey()) { // 非主键
199   - column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition());
200   - }
  188 + column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
  189 + || column.getPrimaryKey()); // 对于主键,更新时需要传递
  190 + // 处理 listOperation 字段
  191 + column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
  192 + && !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递
  193 + // 处理 listOperationCondition 字段
201 194 columnListOperationConditionMappings.entrySet().stream()
202   - .filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
  195 + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
203 196 .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
  197 + if (column.getListOperationCondition() == null) {
  198 + column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition());
  199 + }
  200 + // 处理 listOperationResult 字段
  201 + column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField()));
204 202 }
205 203  
206 204 private void processColumnUI(ToolCodegenColumnDO column) {
207 205 // 基于后缀进行匹配
208 206 columnHtmlTypeMappings.entrySet().stream()
209   - .filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey()))
  207 + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
210 208 .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
211 209 // 如果是 Boolean 类型时,设置为 radio 类型.
212 210 // 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.
... ...
src/main/resources/codegen/dal/do.vm 0 → 100644
  1 +import com.baomidou.mybatisplus.annotation.*;
  2 +import lombok.*;
  3 +import java.util.*;
  4 +
  5 +/**
  6 +* ${table.description}
  7 +*/
  8 +@TableName("${table.tableName}")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +@Builder
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +public class ${table.tableName}DO extends BaseDO {
  16 +
  17 +#foreach ($column in $columns)
  18 + /**
  19 + * ${column.columnComment}
  20 + */
  21 +#if(${column.primaryKey} && ${column.javaType} != 'String')
  22 + @TableId
  23 +#end
  24 +#if(${column.primaryKey} && ${column.javaType} == 'String')
  25 + @TableId(type = IdType.INPUT)
  26 +#end
  27 + private ${column.javaType} ${column.javaField};
  28 +#end
  29 +
  30 +}
... ...
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngineTest.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
  2 +
  3 +import cn.iocoder.dashboard.TestApplication;
  4 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenColumnMapper;
  5 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dao.coegen.ToolCodegenTableMapper;
  6 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO;
  7 +import cn.iocoder.dashboard.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenTableDO;
  8 +import org.junit.jupiter.api.Test;
  9 +import org.springframework.boot.test.context.SpringBootTest;
  10 +
  11 +import javax.annotation.Resource;
  12 +import java.util.List;
  13 +
  14 +@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  15 +public class ToolCodegenEngineTest {
  16 +
  17 + @Resource
  18 + private ToolCodegenTableMapper codegenTableMapper;
  19 + @Resource
  20 + private ToolCodegenColumnMapper codegenColumnMapper;
  21 +
  22 + @Resource
  23 + private ToolCodegenEngine codegenEngine;
  24 +
  25 + @Test
  26 + public void testExecute() {
  27 + ToolCodegenTableDO table = codegenTableMapper.selectById(8);
  28 + List<ToolCodegenColumnDO> columns = codegenColumnMapper.selectByTableId(table.getId());
  29 + codegenEngine.execute(table, columns);
  30 + }
  31 +
  32 +}
... ...
src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
  2 +
  3 +import cn.iocoder.dashboard.TestApplication;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.context.SpringBootTest;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import static org.junit.jupiter.api.Assertions.*;
  10 +
  11 +@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  12 +class ToolCodegenServiceImplTest {
  13 +
  14 + @Resource
  15 + private ToolCodegenServiceImpl toolCodegenService;
  16 +
  17 + @Test
  18 + public void tetCreateCodegenTable() {
  19 + toolCodegenService.createCodegenTable("sys_dict_type");
  20 + }
  21 +
  22 +}
... ...