From 1bea2ea7f8034863a8f994e006df01070865760e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 1 Feb 2021 00:48:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5=20Velocity=20=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E5=BC=95=E6=93=8E=EF=BC=8C=E7=94=9F=E6=88=90=E4=BB=A3?= =?UTF-8?q?=E7=A0=81~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ++ .../mysql/dataobject/dict/SysDictTypeDO.java | 7 +- .../dao/coegen/ToolCodegenColumnMapper.java | 10 +++ .../codegen/ToolCodegenColumnDO.java | 9 ++- .../codegen/impl/ToolCodegenEngine.java | 44 +++++++++++++ .../codegen/impl/ToolCodegenServiceImpl.java | 64 +++++++++---------- src/main/resources/codegen/dal/do.vm | 30 +++++++++ .../codegen/impl/ToolCodegenEngineTest.java | 32 ++++++++++ .../impl/ToolCodegenServiceImplTest.java | 22 +++++++ 9 files changed, 187 insertions(+), 38 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java create mode 100644 src/main/resources/codegen/dal/do.vm create mode 100644 src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngineTest.java create mode 100644 src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImplTest.java diff --git a/pom.xml b/pom.xml index dd9fbe7d06..d93101c897 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ 1.4.1.Final 5.5.6 2.2.7 + 2.2 @@ -221,6 +222,12 @@ ${easyexcel.verion} + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictTypeDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictTypeDO.java index e9816a5bd5..bb663d1825 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictTypeDO.java +++ b/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.TableId; 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") @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class SysDictTypeDO extends BaseDO { /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dao/coegen/ToolCodegenColumnMapper.java b/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dao/coegen/ToolCodegenColumnMapper.java index 9e88678f4e..ee570ba4fa 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dao/coegen/ToolCodegenColumnMapper.java +++ b/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.modules.tool.dal.mysql.dataobject.codegen.ToolCodegenColumnDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface ToolCodegenColumnMapper extends BaseMapperX { + + default List selectByTableId(Long tableId) { + return selectList(new QueryWrapper() + .eq("table_id", tableId) + .orderByAsc("ordinal_position")); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dataobject/codegen/ToolCodegenColumnDO.java b/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dataobject/codegen/ToolCodegenColumnDO.java index cebb373439..4cc7e9a333 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/tool/dal/mysql/dataobject/codegen/ToolCodegenColumnDO.java +++ b/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; /** - * 是否为 List 查询操作的返回字段 + * 是否为 List 查询操作的字段 */ - private Boolean listOperationResult; + private Boolean listOperation; /** * List 查询操作的条件类型 - * 如果为空,则说明不是查询字段 * * 枚举 {@link ToolCodegenColumnListConditionEnum} */ private String listOperationCondition; + /** + * 是否为 List 查询操作的返回字段 + */ + private Boolean listOperationResult; // ========== UI 相关字段 ========== diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java b/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java new file mode 100644 index 0000000000..8e89e4e8c4 --- /dev/null +++ b/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 columns) { + Map 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); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java index d1094539dd..d8b5b2421d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java +++ b/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.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; 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 com.google.common.collect.Sets; import org.springframework.stereotype.Service; @@ -60,8 +53,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { /** * 新增操作,不需要传递的字段 */ - private static final Set CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet( - "id"); + private static final Set CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); /** * 修改操作,不需要传递的字段 */ @@ -69,11 +61,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { /** * 列表操作的条件,不需要传递的字段 */ - private static final Set LIST_OPERATION_CONDITION_COLUMN = Sets.newHashSet(); + private static final Set LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); /** * 列表操作的结果,不需要返回的字段 */ - private static final Set LIST_OPERATION_RESULT_COLUMN = Sets.newHashSet(); + private static final Set LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet(); /** * Java 类型与 MySQL 类型的映射关系 @@ -90,13 +82,15 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { .build(); static { + // 处理 OPERATION 相关的字段 Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> { CREATE_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 @@ -134,7 +128,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { columns.forEach(column -> { initColumnDefault(column); column.setTableId(table.getId()); - codegenColumnMapper.insert(column); + codegenColumnMapper.insert(column); // TODO 批量插入 }); return table.getId(); } @@ -150,10 +144,11 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { table.setBusinessName(StrUtil.subAfter(table.getTableName(), '_', false)); // 第一个 _ 前缀的后面,作为 module 名字 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)); table.setAuthor("芋艿"); // TODO 稍后改成创建人 + table.setTemplateType(ToolCodegenTemplateTypeEnum.CRUD.getType()); } /** @@ -175,7 +170,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { column.setJavaField(StrUtil.toCamelCase(column.getColumnName())); // 处理 dictType 字段,暂无 // 处理 javaType 字段 - String dbType = StrUtil.subBefore(column.getColumnName(), ')', false); + String dbType = StrUtil.subBefore(column.getColumnType(), '(', false); javaTypeMappings.entrySet().stream() .filter(entry -> entry.getValue().contains(dbType)) .findFirst().ifPresent(entry -> column.setJavaType(entry.getKey())); @@ -187,26 +182,29 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { private void processColumnOperation(ToolCodegenColumnDO column) { // 处理 createOperation 字段 - column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getColumnName()) - && !column.getPrimaryKey()); // 非主键 + column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + && !column.getPrimaryKey()); // 对于主键,创建时无需传递 // 处理 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.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() + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey())) + .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition())); + if (column.getListOperationCondition() == null) { column.setListOperationCondition(ToolCodegenColumnListConditionEnum.EQ.getCondition()); } - columnListOperationConditionMappings.entrySet().stream() - .filter(entry -> StrUtil.endWithIgnoreCase(column.getColumnName(), entry.getKey())) - .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition())); + // 处理 listOperationResult 字段 + column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField())); } private void processColumnUI(ToolCodegenColumnDO column) { // 基于后缀进行匹配 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())); // 如果是 Boolean 类型时,设置为 radio 类型. // 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型. diff --git a/src/main/resources/codegen/dal/do.vm b/src/main/resources/codegen/dal/do.vm new file mode 100644 index 0000000000..0e5db0e7b7 --- /dev/null +++ b/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 + +} diff --git a/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngineTest.java b/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngineTest.java new file mode 100644 index 0000000000..faf4d850bd --- /dev/null +++ b/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 columns = codegenColumnMapper.selectByTableId(table.getId()); + codegenEngine.execute(table, columns); + } + +} diff --git a/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImplTest.java b/src/test/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImplTest.java new file mode 100644 index 0000000000..f534e97696 --- /dev/null +++ b/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"); + } + +}