Browse Source

新增代码生成部分代码

hubin 9 tháng trước cách đây
mục cha
commit
6f46b920d7

+ 17 - 5
src/main/java/com/aizuda/boot/modules/gen/controller/GenTableController.java

@@ -1,15 +1,20 @@
 package com.aizuda.boot.modules.gen.controller;
 
+import com.aizuda.boot.modules.gen.entity.dto.GenDTO;
+import com.aizuda.boot.modules.gen.entity.vo.GenVO;
 import com.aizuda.boot.modules.gen.service.IGenTableService;
 import com.aizuda.core.api.ApiController;
 import com.baomidou.kisso.annotation.Permission;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * 代码生成业务表 前端控制器
  *
@@ -23,11 +28,18 @@ import org.springframework.web.bind.annotation.RestController;
 public class GenTableController extends ApiController {
     private IGenTableService genTableService;
 
-    @Operation(summary = "测试")
-    @Permission("gen:table:gen")
-    @PostMapping("/gen")
-    public boolean gen() {
-        return genTableService.gen();
+    @Operation(summary = "预览")
+    @Permission("gen:table:preview")
+    @PostMapping("/preview")
+    public List<GenVO> preview(@Validated GenDTO dto) {
+        return genTableService.preview(dto);
+    }
+
+    @Operation(summary = "下载")
+    @Permission("gen:table:download")
+    @PostMapping("/download")
+    public void download(@Validated GenDTO dto) {
+        genTableService.download(response, dto);
     }
 
 }

+ 6 - 4
src/main/java/com/aizuda/boot/modules/gen/entity/GenTemplate.java

@@ -3,12 +3,11 @@ package com.aizuda.boot.modules.gen.entity;
 import com.aizuda.core.bean.BaseEntity;
 import com.aizuda.core.validation.Create;
 import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.Size;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Setter;
 import lombok.Getter;
+import lombok.Setter;
 
 /**
  * 代码生成模板表
@@ -29,7 +28,6 @@ public class GenTemplate extends BaseEntity {
 
 	@Schema(description = "模板内容")
 	@NotBlank(groups = Create.class)
-	@Size(max = 2147483647)
 	private String tplContent;
 
 	@Schema(description = "输出文件")
@@ -37,4 +35,8 @@ public class GenTemplate extends BaseEntity {
 	@Size(max = 255)
 	private String outFile;
 
+	@Schema(description = "模板描述")
+	@Size(max = 255)
+	private String remark;
+
 }

+ 33 - 0
src/main/java/com/aizuda/boot/modules/gen/entity/dto/GenDTO.java

@@ -0,0 +1,33 @@
+package com.aizuda.boot.modules.gen.entity.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class GenDTO {
+
+    @Schema(description = "数据源ID,默认当前数据源")
+    private Long databaseId;
+
+    @Schema(description = "作者")
+    private String author;
+
+    @Schema(description = "项目模块")
+    @NotBlank
+    private String module;
+
+    @Schema(description = "表名,多个英文逗号分隔")
+    @NotBlank
+    private String tableName;
+
+    @Schema(description = "模板ID列表")
+    @NotEmpty
+    private List<Long> templateIds;
+
+}

+ 24 - 0
src/main/java/com/aizuda/boot/modules/gen/entity/vo/GenVO.java

@@ -0,0 +1,24 @@
+
+package com.aizuda.boot.modules.gen.entity.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class GenVO {
+
+    @Schema(description = "模板名称")
+    private String tplName;
+
+    @Schema(description = "模板内容")
+    private String tplContent;
+
+    @Schema(description = "输出文件")
+    private String outFile;
+
+    @Schema(description = "模板描述")
+    private String remark;
+}

+ 9 - 1
src/main/java/com/aizuda/boot/modules/gen/service/IGenTableService.java

@@ -1,5 +1,11 @@
 package com.aizuda.boot.modules.gen.service;
 
+import com.aizuda.boot.modules.gen.entity.dto.GenDTO;
+import com.aizuda.boot.modules.gen.entity.vo.GenVO;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
 /**
  * 代码生成业务表 服务类
  *
@@ -8,5 +14,7 @@ package com.aizuda.boot.modules.gen.service;
  */
 public interface IGenTableService {
 
-    boolean gen();
+    List<GenVO> preview(GenDTO dto);
+
+    void download(HttpServletResponse response, GenDTO dto);
 }

+ 160 - 24
src/main/java/com/aizuda/boot/modules/gen/service/impl/GenTableServiceImpl.java

@@ -1,22 +1,39 @@
 package com.aizuda.boot.modules.gen.service.impl;
 
+import com.aizuda.boot.modules.gen.entity.GenDatabase;
+import com.aizuda.boot.modules.gen.entity.GenTemplate;
+import com.aizuda.boot.modules.gen.entity.dto.GenDTO;
+import com.aizuda.boot.modules.gen.entity.vo.GenVO;
+import com.aizuda.boot.modules.gen.service.IGenDatabaseService;
 import com.aizuda.boot.modules.gen.service.IGenTableService;
+import com.aizuda.boot.modules.gen.service.IGenTemplateService;
+import com.aizuda.common.toolkit.CollectionUtils;
+import com.aizuda.core.api.ApiAssert;
 import com.aizuda.core.bean.BaseEntity;
+import com.aizuda.service.web.UserSession;
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.generator.config.*;
 import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
 import com.baomidou.mybatisplus.generator.config.rules.DateType;
 import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
 import com.baomidou.mybatisplus.generator.fill.Column;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
+import org.apache.commons.collections.MapUtils;
+import org.apache.ibatis.type.JdbcType;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.stereotype.Service;
 
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 /**
  * 代码生成业务表 服务实现类
@@ -27,21 +44,95 @@ import java.util.Map;
 @Service
 @AllArgsConstructor
 public class GenTableServiceImpl implements IGenTableService {
+    private IGenDatabaseService genDatabaseService;
+    private IGenTemplateService genTemplateService;
     private DataSourceProperties dsp;
 
     @Override
-    public boolean gen() {
-        DataSourceConfig.Builder dataSource = new DataSourceConfig.Builder(dsp.getUrl(), dsp.getUsername(), dsp.getPassword());
+    public List<GenVO> preview(GenDTO dto) {
+        List<GenTemplate> genTemplates = genTemplateService.listByIds(dto.getTemplateIds());
+        ApiAssert.fail(CollectionUtils.isEmpty(genTemplates), "请选择生成模板");
+
+        // 生成预览内容
+        ConfigBuilder configBuilder = this.buildConfigBuilder(dto);
+        TableInfo tableInfo = this.buildConfigBuilder(dto).getTableInfoList().get(0);
+        VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();
+        templateEngine.init(configBuilder);
+        return genTemplates.stream().map(t -> {
+            GenVO vo = new GenVO();
+            try {
+                Map<String, Object> objectMap = this.getObjectMap(configBuilder, tableInfo);
+                vo.setTplName(t.getTplName());
+                vo.setTplContent(templateEngine.writer(objectMap, tableInfo.getEntityName(), t.getTplContent()));
+                vo.setOutFile(t.getOutFile());
+                vo.setRemark(t.getRemark());
+            } catch (Exception e) {
+                ApiAssert.fail("模板【" + t.getTplName() + "】内容异常");
+            }
+            return vo;
+        }).toList();
+    }
+
+    @Override
+    public void download(HttpServletResponse response, GenDTO dto) {
+        List<GenTemplate> genTemplates = genTemplateService.listByIds(dto.getTemplateIds());
+        ApiAssert.fail(CollectionUtils.isEmpty(genTemplates), "请选择生成模板");
+
+        // 生成预览内容
+        ConfigBuilder configBuilder = this.buildConfigBuilder(dto);
+        TableInfo tableInfo = this.buildConfigBuilder(dto).getTableInfoList().get(0);
+        VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();
+        templateEngine.init(configBuilder);
+
+        // 设置响应内容类型
+        response.setContentType("application/zip");
+        response.setHeader("Content-Disposition", "attachment; filename=\"generatedCode.zip\"");
+        // 创建ZIP输出流
+        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
+            // 渲染模板
+            for (GenTemplate gt : genTemplates) {
+                // 创建输出流
+                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+                Map<String, Object> objectMap = this.getObjectMap(configBuilder, tableInfo);
+                String context = templateEngine.writer(objectMap, tableInfo.getEntityName(), gt.getTplContent());
+                byteArrayOutputStream.write(context.getBytes());
+
+                // 创建文件内容
+                String packageName = configBuilder.getPackageConfig().getParent();
+                ZipEntry zipEntry = new ZipEntry(packageName.replace('.', '/') + "/" +
+                        String.format(gt.getOutFile(), tableInfo.getEntityName()));
+                zos.putNextEntry(zipEntry);
+                zos.write(byteArrayOutputStream.toByteArray());
+                zos.closeEntry();
+            }
+        } catch (Exception e) {
+            ApiAssert.fail("生成文件异常");
+        }
+    }
+
+    private ConfigBuilder buildConfigBuilder(GenDTO dto) {
+        DataSourceConfig.Builder dataSource;
+        if (null != dto.getDatabaseId()) {
+            GenDatabase gb = genDatabaseService.getById(dto.getDatabaseId());
+            ApiAssert.fail(null == gb, "指定数据源不存在");
+            dataSource = new DataSourceConfig.Builder(gb.url(), gb.getUsername(), gb.getPassword());
+        } else {
+            dataSource = new DataSourceConfig.Builder(dsp.getUrl(), dsp.getUsername(), dsp.getPassword());
+        }
+
         // 全局配置
-        GlobalConfig.Builder globalConfig = new GlobalConfig.Builder().author("青苗")
-                .outputDir("C://aizuda-code")
+        String author = dto.getAuthor();
+        if (StringUtils.isBlank(author)) {
+            author = UserSession.getLoginInfo().getUsername();
+        }
+        GlobalConfig.Builder globalConfig = new GlobalConfig.Builder().author(author)
                 .dateType(DateType.ONLY_DATE)
                 .enableSwagger();
         // 包配置
-        PackageConfig.Builder packageInfo = new PackageConfig.Builder().parent("com.aizuda.boot.modules.gen");
+        PackageConfig.Builder packageInfo = new PackageConfig.Builder().parent("com.aizuda.boot.modules." + dto.getModule());
         // 策略配置
         StrategyConfig.Builder strategy = new StrategyConfig.Builder();
-        strategy.addInclude(List.of("sys_user", "sys_role"))
+        strategy.addInclude(Arrays.stream(dto.getTableName().split(",")).toList())
                 .controllerBuilder().enableRestStyle().enableHyphenStyle()
                 .serviceBuilder().superServiceClass("com.aizuda.service.service.IBaseService")
                 .mapperBuilder().superClass("com.aizuda.service.mapper.CrudMapper")
@@ -57,30 +148,20 @@ public class GenTableServiceImpl implements IGenTableService {
                 .superClass(BaseEntity.class);
         // 注入配置
         InjectionConfig.Builder injection = new InjectionConfig.Builder();
-        // 模板配置
-        TemplateConfig.Builder template = new TemplateConfig.Builder().disable(TemplateType.XML);
         // 模板渲染引擎 new CodeTemplateEngine()
-        ConfigBuilder config = new ConfigBuilder(packageInfo.build(), dataSource.build(), strategy.build(), template.build(),
+        return new ConfigBuilder(packageInfo.build(), dataSource.build(), strategy.build(), null,
                 globalConfig.build(), injection.build());
-        List<TableInfo> tableInfos = config.getTableInfoList();
-        VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();
-        templateEngine.init(config);
-        tableInfos.forEach((tableInfo) -> {
-            Map<String, Object> objectMap = this.getObjectMap(config, tableInfo);
-            try {
-                String tmp = templateEngine.writer(objectMap, tableInfo.getEntityName(), "hi ${author}");
-                System.err.println("----dsa----" + tmp);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        });
-        return true;
     }
 
-    public Map<String, Object> getObjectMap(ConfigBuilder config, TableInfo tableInfo) {
+    private Map<String, Object> getObjectMap(ConfigBuilder config, TableInfo tableInfo) {
+
+        // 验证注解
+        this.validationAnnotations(tableInfo);
+
+        // 策略配置
         StrategyConfig strategyConfig = config.getStrategyConfig();
         Map<String, Object> controllerData = strategyConfig.controller().renderData(tableInfo);
-        Map<String, Object> objectMap = new HashMap(controllerData);
+        Map<String, Object> objectMap = new HashMap<>(controllerData);
         Map<String, Object> mapperData = strategyConfig.mapper().renderData(tableInfo);
         objectMap.putAll(mapperData);
         Map<String, Object> serviceData = strategyConfig.service().renderData(tableInfo);
@@ -109,4 +190,59 @@ public class GenTableServiceImpl implements IGenTableService {
         objectMap.put("entity", tableInfo.getEntityName());
         return objectMap;
     }
+
+    /**
+     * 追加校验注解
+     */
+    protected void validationAnnotations(TableInfo tableInfo) {
+        List<TableField> fields = tableInfo.getFields();
+        fields.forEach(tableField -> {
+            TableField.MetaInfo metaInfo = tableField.getMetaInfo();
+            final String lt = "\t";
+            final String lnt = "\n\t";
+            final JdbcType jdbcType = metaInfo.getJdbcType();
+            StringBuilder annotations = new StringBuilder();
+            boolean tabLine = false;
+            if (!metaInfo.isNullable()) {
+                annotations.append(lt);
+                if (JdbcType.VARCHAR == jdbcType) {
+                    annotations.append("@NotBlank(groups = Create.class)");
+                    tableInfo.addImportPackages("jakarta.validation.constraints.NotBlank");
+                } else {
+                    annotations.append("@NotNull(groups = Create.class)");
+                    tableInfo.addImportPackages("jakarta.validation.constraints.NotNull");
+                }
+                tabLine = true;
+            }
+            if (JdbcType.VARCHAR == jdbcType) {
+                annotations.append(tabLine ? lnt : lt);
+                annotations.append("@Size(max = ").append(metaInfo.getLength()).append(")");
+                tableInfo.addImportPackages("jakarta.validation.constraints.Size");
+            } else if (JdbcType.BIGINT == jdbcType
+                    || JdbcType.INTEGER == jdbcType
+                    || JdbcType.TINYINT == jdbcType
+                    || JdbcType.SMALLINT == jdbcType
+                    || JdbcType.BIT == jdbcType
+                    || JdbcType.FLOAT == jdbcType
+                    || JdbcType.DOUBLE == jdbcType
+                    || JdbcType.DECIMAL == jdbcType) {
+                annotations.append(tabLine ? lnt : lt);
+                annotations.append("@PositiveOrZero");
+                tableInfo.addImportPackages("jakarta.validation.constraints.PositiveOrZero");
+            }
+            Map<String, Object> customMap = tableField.getCustomMap();
+            if (MapUtils.isEmpty(customMap)) {
+                customMap = new HashMap<>();
+            }
+            String va = annotations.toString();
+            if (org.apache.commons.lang3.StringUtils.isNotBlank(va)) {
+                va += lnt;
+                tableInfo.addImportPackages("com.aizuda.core.validation.Create");
+            } else {
+                va = lt;
+            }
+            customMap.put("validationAnnotations", va);
+            tableField.setCustomMap(customMap);
+        });
+    }
 }