Commit 01a55b93c2dc9019d85ea5548ba82d26c32476e5

Authored by YunaiV
1 parent f5ea270b

代码生成:增加更全的 tree 场景下的新增/修改校验

yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
@@ -324,10 +324,14 @@ public class CodegenEngine { @@ -324,10 +324,14 @@ public class CodegenEngine {
324 324
325 // 特殊:树表专属逻辑 325 // 特殊:树表专属逻辑
326 if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { 326 if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
327 - bindingMap.put("treeParentColumn", CollUtil.findOne(columns,  
328 - column -> Objects.equals(column.getId(), table.getTreeParentColumnId())));  
329 - bindingMap.put("treeNameColumn", CollUtil.findOne(columns,  
330 - column -> Objects.equals(column.getId(), table.getTreeNameColumnId()))); 327 + CodegenColumnDO treeParentColumn = CollUtil.findOne(columns,
  328 + column -> Objects.equals(column.getId(), table.getTreeParentColumnId()));
  329 + bindingMap.put("treeParentColumn", treeParentColumn);
  330 + bindingMap.put("treeParentColumn_javaField_underlineCase", toUnderlineCase(treeParentColumn.getJavaField()));
  331 + CodegenColumnDO treeNameColumn = CollUtil.findOne(columns,
  332 + column -> Objects.equals(column.getId(), table.getTreeNameColumnId()));
  333 + bindingMap.put("treeNameColumn", treeNameColumn);
  334 + bindingMap.put("treeNameColumn_javaField_underlineCase", toUnderlineCase(treeNameColumn.getJavaField()));
331 } 335 }
332 336
333 // 特殊:主子表专属逻辑 337 // 特殊:主子表专属逻辑
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm
@@ -28,6 +28,11 @@ import ${BaseDOClassName}; @@ -28,6 +28,11 @@ import ${BaseDOClassName};
28 @AllArgsConstructor 28 @AllArgsConstructor
29 public class ${table.className}DO extends BaseDO { 29 public class ${table.className}DO extends BaseDO {
30 30
  31 +## 特殊:树表专属逻辑
  32 +#if ( $table.templateType == 2 )
  33 + public static final Long ${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT = 0L;
  34 +
  35 +#end
31 #foreach ($column in $columns) 36 #foreach ($column in $columns)
32 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 37 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
33 /** 38 /**
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm
@@ -68,9 +68,14 @@ public interface ${table.className}Mapper extends BaseMapperX<${table.className} @@ -68,9 +68,14 @@ public interface ${table.className}Mapper extends BaseMapperX<${table.className}
68 68
69 ## 特殊:树表专属逻辑 69 ## 特殊:树表专属逻辑
70 #if ( $table.templateType == 2 ) 70 #if ( $table.templateType == 2 )
71 -#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写  
72 - default Long selectCountBy${ParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) {  
73 - return selectCount(${table.className}DO::get${ParentJavaField}, ${treeParentColumn.javaField}); 71 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  72 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  73 + default ${table.className}DO selectBy${TreeParentJavaField}And${TreeNameJavaField}(Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
  74 + return selectOne(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}, ${table.className}DO::get${TreeNameJavaField}, ${treeNameColumn.javaField});
  75 + }
  76 +
  77 + default Long selectCountBy${TreeParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) {
  78 + return selectCount(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField});
74 } 79 }
75 80
76 #end 81 #end
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm
@@ -4,4 +4,7 @@ ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorC @@ -4,4 +4,7 @@ ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorC
4 ## 特殊:树表专属逻辑 4 ## 特殊:树表专属逻辑
5 #if ( $table.templateType == 2 ) 5 #if ( $table.templateType == 2 )
6 ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除"); 6 ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除");
  7 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级${table.classComment}不存在");
  8 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父${table.classComment}");
  9 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该${treeNameColumn.columnComment}的${table.classComment}");
7 #end 10 #end
8 \ No newline at end of file 11 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
@@ -50,6 +50,16 @@ public class ${table.className}ServiceImpl implements ${table.className}Service @@ -50,6 +50,16 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
50 @Transactional(rollbackFor = Exception.class) 50 @Transactional(rollbackFor = Exception.class)
51 #end 51 #end
52 public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) { 52 public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) {
  53 +## 特殊:树表专属逻辑
  54 +#if ( $table.templateType == 2 )
  55 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  56 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  57 + // 校验${treeParentColumn.columnComment}的有效性
  58 + validateParent${simpleClassName}(null, createReqVO.get${TreeParentJavaField}());
  59 + // 校验${treeNameColumn.columnComment}的唯一性
  60 + validate${simpleClassName}${TreeNameJavaField}Unique(null, createReqVO.get${TreeParentJavaField}(), createReqVO.get${TreeNameJavaField}());
  61 +
  62 +#end
53 // 插入 63 // 插入
54 ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class); 64 ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class);
55 ${classNameVar}Mapper.insert(${classNameVar}); 65 ${classNameVar}Mapper.insert(${classNameVar});
@@ -81,6 +91,16 @@ public class ${table.className}ServiceImpl implements ${table.className}Service @@ -81,6 +91,16 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
81 public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) { 91 public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) {
82 // 校验存在 92 // 校验存在
83 validate${simpleClassName}Exists(updateReqVO.getId()); 93 validate${simpleClassName}Exists(updateReqVO.getId());
  94 +## 特殊:树表专属逻辑
  95 +#if ( $table.templateType == 2 )
  96 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  97 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  98 + // 校验${treeParentColumn.columnComment}的有效性
  99 + validateParent${simpleClassName}(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}());
  100 + // 校验${treeNameColumn.columnComment}的唯一性
  101 + validate${simpleClassName}${TreeNameJavaField}Unique(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}(), updateReqVO.get${TreeNameJavaField}());
  102 +
  103 +#end
84 // 更新 104 // 更新
85 ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class); 105 ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class);
86 ${classNameVar}Mapper.updateById(updateObj); 106 ${classNameVar}Mapper.updateById(updateObj);
@@ -140,6 +160,59 @@ public class ${table.className}ServiceImpl implements ${table.className}Service @@ -140,6 +160,59 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
140 } 160 }
141 } 161 }
142 162
  163 +## 特殊:树表专属逻辑
  164 +#if ( $table.templateType == 2 )
  165 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  166 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  167 + private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) {
  168 + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
  169 + return;
  170 + }
  171 + // 1. 不能设置自己为父${table.classComment}
  172 + if (Objects.equals(id, ${treeParentColumn.javaField})) {
  173 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR);
  174 + }
  175 + // 2. 父${table.classComment}不存在
  176 + ${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
  177 + if (parent${simpleClassName} == null) {
  178 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS);
  179 + }
  180 + // 3. 递归校验父${table.classComment},如果父${table.classComment}是自己的子${table.classComment},则报错,避免形成环路
  181 + if (id == null) { // id 为空,说明新增,不需要考虑环路
  182 + return;
  183 + }
  184 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  185 + // 3.1 校验环路
  186 + ${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}();
  187 + if (Objects.equals(id, ${treeParentColumn.javaField})) {
  188 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD);
  189 + }
  190 + // 3.2 继续递归下一级父${table.classComment}
  191 + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
  192 + break;
  193 + }
  194 + parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
  195 + if (parent${simpleClassName} == null) {
  196 + break;
  197 + }
  198 + }
  199 + }
  200 +
  201 + private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
  202 + ${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField});
  203 + if (${classNameVar} == null) {
  204 + return;
  205 + }
  206 + // 如果 id 为空,说明不用比较是否为相同 id 的${table.classComment}
  207 + if (id == null) {
  208 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
  209 + }
  210 + if (ObjectUtil.notEqual(${classNameVar}.getId(), id)) {
  211 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
  212 + }
  213 + }
  214 +
  215 +#end
143 @Override 216 @Override
144 public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { 217 public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
145 return ${classNameVar}Mapper.selectById(id); 218 return ${classNameVar}Mapper.selectById(id);
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineTest.java
@@ -51,8 +51,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest { @@ -51,8 +51,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
51 .setClassComment("学生").setAuthor("芋道源码") 51 .setClassComment("学生").setAuthor("芋道源码")
52 .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()) 52 .setTemplateType(CodegenTemplateTypeEnum.TREE.getType())
53 .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) 53 .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
54 - .setTreeParentColumnId(22L).setTreeNameColumnId(11L)  
55 - ; 54 + .setTreeParentColumnId(22L).setTreeNameColumnId(11L);
56 CodegenColumnDO idColumn = new CodegenColumnDO().setColumnName("id").setDataType(JdbcType.BIGINT.name()) 55 CodegenColumnDO idColumn = new CodegenColumnDO().setColumnName("id").setDataType(JdbcType.BIGINT.name())
57 .setColumnComment("编号").setNullable(false).setPrimaryKey(true).setAutoIncrement(true) 56 .setColumnComment("编号").setNullable(false).setPrimaryKey(true).setAutoIncrement(true)
58 .setJavaType("Long").setJavaField("id").setExample("1024") 57 .setJavaType("Long").setJavaField("id").setExample("1024")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -141,7 +141,7 @@ public class DeptServiceImpl implements DeptService { @@ -141,7 +141,7 @@ public class DeptServiceImpl implements DeptService {
141 if (dept == null) { 141 if (dept == null) {
142 return; 142 return;
143 } 143 }
144 - // 如果 id 为空,说明不用比较是否为相同 id 的岗位 144 + // 如果 id 为空,说明不用比较是否为相同 id 的部门
145 if (id == null) { 145 if (id == null) {
146 throw exception(DEPT_NAME_DUPLICATE); 146 throw exception(DEPT_NAME_DUPLICATE);
147 } 147 }