Commit 6646aafae810e2068ac98d8ccf62e543db7e2848

Authored by Bujidao
1 parent 78bcd54e

feat(codegen): add backend excel import template generation

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)
... ...