Commit 6646aafae810e2068ac98d8ccf62e543db7e2848
1 parent
78bcd54e
feat(codegen): add backend excel import template generation
Showing
7 changed files
with
132 additions
and
5 deletions
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
| ... | ... | @@ -72,6 +72,8 @@ public class CodegenEngine { |
| 72 | 72 | .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO")) |
| 73 | 73 | .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO")) |
| 74 | 74 | .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO")) |
| 75 | + .put(javaTemplatePath("controller/vo/importExcelVO"), javaModuleImplVOFilePath("ImportExcelVO")) | |
| 76 | + .put(javaTemplatePath("controller/vo/importRespVO"), javaModuleImplVOFilePath("ImportRespVO")) | |
| 75 | 77 | .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath()) |
| 76 | 78 | .put(javaTemplatePath("dal/do"), |
| 77 | 79 | javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO")) | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/controller/controller.vm
| 1 | 1 | package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; |
| 2 | 2 | |
| 3 | 3 | import org.springframework.web.bind.annotation.*; |
| 4 | +import org.springframework.web.multipart.MultipartFile; | |
| 4 | 5 | import ${jakartaPackage}.annotation.Resource; |
| 5 | 6 | import org.springframework.validation.annotation.Validated; |
| 6 | 7 | #if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end |
| ... | ... | @@ -160,6 +161,28 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { |
| 160 | 161 | } |
| 161 | 162 | #end |
| 162 | 163 | |
| 164 | + @GetMapping("/get-import-template") | |
| 165 | + @Operation(summary = "获得导入${table.classComment}模板") | |
| 166 | +#if ($sceneEnum.scene == 1) | |
| 167 | + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | |
| 168 | +#end | |
| 169 | + public void import${simpleClassName}Template(HttpServletResponse response) throws IOException { | |
| 170 | + ExcelUtils.write(response, "${table.classComment}导入模板.xls", "数据", | |
| 171 | + ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class, Collections.emptyList()); | |
| 172 | + } | |
| 173 | + | |
| 174 | + @PostMapping("/import") | |
| 175 | + @Operation(summary = "导入${table.classComment}") | |
| 176 | + @Parameter(name = "file", description = "Excel 文件", required = true) | |
| 177 | +#if ($sceneEnum.scene == 1) | |
| 178 | + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:import')") | |
| 179 | +#end | |
| 180 | + @ApiAccessLog(operateType = IMPORT) | |
| 181 | + public CommonResult<${sceneEnum.prefixClass}${table.className}ImportRespVO> import${simpleClassName}(@RequestParam("file") MultipartFile file) throws Exception { | |
| 182 | + List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> list = ExcelUtils.read(file, ${sceneEnum.prefixClass}${table.className}ImportExcelVO.class); | |
| 183 | + return success(${classNameVar}Service.import${simpleClassName}List(list)); | |
| 184 | + } | |
| 185 | + | |
| 163 | 186 | ## 特殊:主子表专属逻辑 |
| 164 | 187 | #foreach ($subTable in $subTables) |
| 165 | 188 | #set ($index = $foreach.count - 1) |
| ... | ... | @@ -268,4 +291,4 @@ public class ${sceneEnum.prefixClass}${table.className}Controller { |
| 268 | 291 | |
| 269 | 292 | #end |
| 270 | 293 | #end |
| 271 | -} | |
| 272 | 294 | \ No newline at end of file |
| 295 | +} | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/importExcelVO.vm
0 → 100644
| 1 | +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; | |
| 2 | + | |
| 3 | +import cn.idev.excel.annotation.ExcelProperty; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Builder; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.NoArgsConstructor; | |
| 8 | +#foreach ($column in $columns) | |
| 9 | +#if (${column.createOperation} && "$!column.dictType" != "") | |
| 10 | +import ${DictFormatClassName}; | |
| 11 | +import ${DictConvertClassName}; | |
| 12 | +#break | |
| 13 | +#end | |
| 14 | +#end | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * ${table.classComment} Excel 导入 VO | |
| 18 | + */ | |
| 19 | +@Data | |
| 20 | +@Builder | |
| 21 | +@AllArgsConstructor | |
| 22 | +@NoArgsConstructor | |
| 23 | +public class ${sceneEnum.prefixClass}${table.className}ImportExcelVO { | |
| 24 | + | |
| 25 | +## 逐个处理字段 | |
| 26 | +#foreach ($column in $columns) | |
| 27 | +#if (${column.createOperation}) | |
| 28 | +#if ("$!column.dictType" != "") | |
| 29 | + @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class) | |
| 30 | + @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 | |
| 31 | +#else | |
| 32 | + @ExcelProperty("${column.columnComment}") | |
| 33 | +#end | |
| 34 | + private ${column.javaType} ${column.javaField}; | |
| 35 | + | |
| 36 | +#end | |
| 37 | +#end | |
| 38 | +} | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/controller/vo/importRespVO.vm
0 → 100644
| 1 | +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Builder; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.util.Map; | |
| 8 | + | |
| 9 | +@Schema(description = "${sceneEnum.name} - ${table.classComment}导入 Response VO") | |
| 10 | +@Data | |
| 11 | +@Builder | |
| 12 | +public class ${sceneEnum.prefixClass}${table.className}ImportRespVO { | |
| 13 | + | |
| 14 | + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | |
| 15 | + private Integer successCount; | |
| 16 | + | |
| 17 | + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 18 | + private Integer failureCount; | |
| 19 | + | |
| 20 | + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 21 | + private Map<Integer, String> failureRows; | |
| 22 | + | |
| 23 | +} | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/service/service.vm
| ... | ... | @@ -27,6 +27,14 @@ public interface ${table.className}Service { |
| 27 | 27 | ${primaryColumn.javaType} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar}); |
| 28 | 28 | |
| 29 | 29 | /** |
| 30 | + * 导入${table.classComment} | |
| 31 | + * | |
| 32 | + * @param importList 导入信息 | |
| 33 | + * @return 导入结果 | |
| 34 | + */ | |
| 35 | + ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList); | |
| 36 | + | |
| 37 | + /** | |
| 30 | 38 | * 更新${table.classComment} |
| 31 | 39 | * |
| 32 | 40 | * @param ${updateReqVOVar} 更新信息 |
| ... | ... | @@ -162,4 +170,4 @@ public interface ${table.className}Service { |
| 162 | 170 | |
| 163 | 171 | #end |
| 164 | 172 | #end |
| 165 | -} | |
| 166 | 173 | \ No newline at end of file |
| 174 | +} | ... | ... |
yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
| ... | ... | @@ -7,6 +7,7 @@ import org.springframework.validation.annotation.Validated; |
| 7 | 7 | import org.springframework.transaction.annotation.Transactional; |
| 8 | 8 | |
| 9 | 9 | import java.util.*; |
| 10 | +import java.util.concurrent.atomic.AtomicInteger; | |
| 10 | 11 | import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; |
| 11 | 12 | import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; |
| 12 | 13 | ## 特殊:主子表专属逻辑 |
| ... | ... | @@ -93,6 +94,35 @@ public class ${table.className}ServiceImpl implements ${table.className}Service |
| 93 | 94 | } |
| 94 | 95 | |
| 95 | 96 | @Override |
| 97 | + @Transactional(rollbackFor = Exception.class) | |
| 98 | + public ${sceneEnum.prefixClass}${table.className}ImportRespVO import${simpleClassName}List(List<${sceneEnum.prefixClass}${table.className}ImportExcelVO> importList) { | |
| 99 | + if (CollUtil.isEmpty(importList)) { | |
| 100 | + return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | |
| 101 | + .successCount(0) | |
| 102 | + .failureCount(0) | |
| 103 | + .failureRows(new LinkedHashMap<>()) | |
| 104 | + .build(); | |
| 105 | + } | |
| 106 | + AtomicInteger successCount = new AtomicInteger(); | |
| 107 | + Map<Integer, String> failureRows = new LinkedHashMap<>(); | |
| 108 | + AtomicInteger index = new AtomicInteger(1); | |
| 109 | + importList.forEach(importItem -> { | |
| 110 | + int currentIndex = index.getAndIncrement(); | |
| 111 | + try { | |
| 112 | + create${simpleClassName}(BeanUtils.toBean(importItem, ${saveReqVOClass}.class)); | |
| 113 | + successCount.incrementAndGet(); | |
| 114 | + } catch (Exception ex) { | |
| 115 | + failureRows.put(currentIndex, ex.getMessage()); | |
| 116 | + } | |
| 117 | + }); | |
| 118 | + return ${sceneEnum.prefixClass}${table.className}ImportRespVO.builder() | |
| 119 | + .successCount(successCount.get()) | |
| 120 | + .failureCount(failureRows.size()) | |
| 121 | + .failureRows(failureRows) | |
| 122 | + .build(); | |
| 123 | + } | |
| 124 | + | |
| 125 | + @Override | |
| 96 | 126 | ## 特殊:主子表专属逻辑(非 ERP 模式) |
| 97 | 127 | #if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) |
| 98 | 128 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -359,6 +389,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service |
| 359 | 389 | #else |
| 360 | 390 | #if ( $subTable.subJoinMany) |
| 361 | 391 | private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { |
| 392 | + if (CollUtil.isEmpty(list)) { | |
| 393 | + return; | |
| 394 | + } | |
| 362 | 395 | list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean()); |
| 363 | 396 | ${subClassNameVars.get($index)}Mapper.insertBatch(list); |
| 364 | 397 | } |
| ... | ... | @@ -416,4 +449,4 @@ public class ${table.className}ServiceImpl implements ${table.className}Service |
| 416 | 449 | #end |
| 417 | 450 | |
| 418 | 451 | #end |
| 419 | -} | |
| 420 | 452 | \ No newline at end of file |
| 453 | +} | ... | ... |
yudao-module-infra/src/main/resources/codegen/sql/sql.vm
| 1 | 1 | ## 通用变量定义 |
| 2 | -#set ($functionNames = ['查询', '创建', '更新', '删除', '导出']) | |
| 3 | -#set ($functionOps = ['query', 'create', 'update', 'delete', 'export']) | |
| 2 | +#set ($functionNames = ['查询', '创建', '更新', '删除', '导出', '导入']) | |
| 3 | +#set ($functionOps = ['query', 'create', 'update', 'delete', 'export', 'import']) | |
| 4 | 4 | ## |
| 5 | 5 | ## 宏定义:生成按钮 SQL(通用部分) |
| 6 | 6 | #macro(insertButtonSql $parentIdVar) | ... | ... |