xiejun
2024-11-01 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a
Source/BladeX-Tool/blade-starter-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,356 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill åº„骞 (smallchill@163.com)
 */
package org.springblade.develop.support;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Mapper;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import static org.springblade.develop.constant.DevelopConstant.*;
/**
 * ä»£ç ç”Ÿæˆå™¨é…ç½®ç±»
 *
 * @author Chill
 */
@Data
@Slf4j
public class BladeCodeGenerator {
   /**
    * ä»£ç é£Žæ ¼
    */
   private String codeStyle = SABER_NAME;
   /**
    * ä»£ç æ¨¡å—名称
    */
   private String codeName;
   /**
    * æ¨¡åž‹ç¼–号
    */
   private String modelCode;
   /**
    * æ¨¡åž‹å®žä½“ç±»
    */
   private String modelClass;
   /**
    * ä»£ç æ‰€åœ¨æœåŠ¡å
    */
   private String serviceName = "blade-service";
   /**
    * ä»£ç ç”Ÿæˆçš„包名
    */
   private String packageName = "org.springblade.test";
   /**
    * æ¨¡ç‰ˆç±»åž‹
    */
   private String templateType;
   /**
    * ä½œè€…信息
    */
   private String author;
   /**
    * å­è¡¨æ¨¡åž‹ä¸»é”®
    */
   private String subModelId;
   /**
    * å­è¡¨ç»‘定外键
    */
   private String subFkId;
   /**
    * æ ‘主键字段
    */
   private String treeId;
   /**
    * æ ‘父主键字段
    */
   private String treePid;
   /**
    * æ ‘名称字段
    */
   private String treeName;
   /**
    * ä»£ç åŽç«¯ç”Ÿæˆçš„地址
    */
   private String packageDir;
   /**
    * ä»£ç å‰ç«¯ç”Ÿæˆçš„地址
    */
   private String packageWebDir;
   /**
    * éœ€è¦åŽ»æŽ‰çš„è¡¨å‰ç¼€
    */
   private String[] tablePrefix = {"blade_"};
   /**
    * éœ€è¦ç”Ÿæˆçš„表名(两者只能取其一)
    */
   private String[] includeTables = {"blade_test"};
   /**
    * éœ€è¦æŽ’除的表名(两者只能取其一)
    */
   private String[] excludeTables = {};
   /**
    * æ˜¯å¦åŒ…含基础业务字段
    */
   private Boolean hasSuperEntity = Boolean.TRUE;
   /**
    * æ˜¯å¦åŒ…含包装器
    */
   private Boolean hasWrapper = Boolean.TRUE;
   /**
    * æ˜¯å¦åŒ…含远程调用
    */
   private Boolean hasFeign = Boolean.FALSE;
   /**
    * æ˜¯å¦åŒ…含服务名
    */
   private Boolean hasServiceName = Boolean.FALSE;
   /**
    * åŸºç¡€ä¸šåŠ¡å­—æ®µ
    */
   private String[] superEntityColumns = {"create_time", "create_user", "create_dept", "update_time", "update_user", "status", "is_deleted"};
   /**
    * ç§Ÿæˆ·å­—段
    */
   private String tenantColumn = "tenant_id";
   /**
    * æ•°æ®åº“驱动名
    */
   private String driverName;
   /**
    * æ•°æ®åº“链接地址
    */
   private String url;
   /**
    * æ•°æ®åº“用户名
    */
   private String username;
   /**
    * æ•°æ®åº“密码
    */
   private String password;
   /**
    * æ•°æ®æ¨¡åž‹
    */
   private Map<String, Object> model;
   /**
    * æ•°æ®åŽŸåž‹
    */
   private List<Map<String, Object>> prototypes;
   /**
    * å­æ•°æ®æ¨¡åž‹
    */
   private Map<String, Object> subModel;
   /**
    * å­æ•°æ®åŽŸåž‹
    */
   private List<Map<String, Object>> subPrototypes;
   /**
    * ä»£ç ç”Ÿæˆæ‰§è¡Œ
    */
   public void run() {
      // ä¸»æ¨¡å—代码生成
      getAutoGenerator(getCustomMap(TEMPLATE_MAIN), getCustomFile(TEMPLATE_MAIN)).templateEngine(new BladeTemplateEngine(getOutputDir(), getOutputWebDir())).execute();
      // å­æ¨¡å—代码生成
      if (Func.equals(templateType, TEMPLATE_SUB) && StringUtil.isNotBlank(subModelId)) {
         getAutoGenerator(getCustomMap(TEMPLATE_SUB), getCustomFile(TEMPLATE_SUB)).templateEngine(new BladeTemplateEngine(getOutputDir(), getOutputWebDir())).execute();
      }
   }
   /**
    * è®¾ç½® customMap
    */
   private Map<String, Object> getCustomMap(String generateType) {
      List<Map<String, Object>> prototypeList;
      String[] split = packageName.split("\\.");
      String serviceCode = split[split.length - 1];
      Map<String, Object> customMap = new HashMap<>(11);
      customMap.put("generateType", generateType);
      customMap.put("codeName", codeName);
      customMap.put("serviceName", serviceName);
      customMap.put("serviceCode", serviceCode);
      customMap.put("packageName", packageName);
      customMap.put("tenantColumn", tenantColumn);
      customMap.put("hasWrapper", hasWrapper);
      customMap.put("hasServiceName", hasServiceName);
      customMap.put("templateType", templateType);
      customMap.put("author", author);
      customMap.put("subModelId", subModelId);
      customMap.put("subFkId", subFkId);
      customMap.put("treeId", treeId);
      customMap.put("treePid", treePid);
      customMap.put("treeName", treeName);
      customMap.put("subFkIdHump", StringUtil.underlineToHump(subFkId));
      customMap.put("treeIdHump", StringUtil.underlineToHump(treeId));
      customMap.put("treePidHump", StringUtil.underlineToHump(treePid));
      if (Func.equals(generateType, TEMPLATE_SUB)) {
         prototypeList = subPrototypes;
         customMap.put("model", subModel);
         customMap.put("prototypes", subPrototypes);
         customMap.put("modelCode", subModel.get("modelCode"));
         customMap.put("modelClass", subModel.get("modelClass"));
         customMap.put("modelTable", subModel.get("modelTable"));
      } else {
         prototypeList = prototypes;
         customMap.put("model", model);
         customMap.put("prototypes", prototypes);
         customMap.put("subModel", subModel);
         customMap.put("subPrototypes", subPrototypes);
         customMap.put("modelCode", model.get("modelCode"));
         customMap.put("modelClass", model.get("modelClass"));
         customMap.put("modelTable", model.get("modelTable"));
      }
      List<String> propertyImport = prototypeList.stream().filter(prototype -> {
         String propertyType = String.valueOf(prototype.get("propertyType"));
         return !"String".equals(propertyType) && !"Integer".equals(propertyType) && !"Long".equals(propertyType);
      }).map(prototype -> String.valueOf(prototype.get("propertyEntity"))).distinct().collect(Collectors.toList());
      customMap.put("propertyImport", propertyImport);
      return customMap;
   }
   /**
    * è®¾ç½® customFile
    */
   private Map<String, String> getCustomFile(String type) {
      Map<String, String> customFile = new HashMap<>(15);
      if (!Func.equals(type, TEMPLATE_SUB)) {
         customFile.put("menu.sql", "/templates/sql/menu.sql.btl");
      }
      customFile.put("entityVO.java", "/templates/api/entityVO.java.btl");
      customFile.put("entityDTO.java", "/templates/api/entityDTO.java.btl");
      if (hasWrapper) {
         customFile.put("wrapper.java", "/templates/api/wrapper.java.btl");
      }
      if (hasFeign) {
         customFile.put("feign.java", "/templates/api/feign.java.btl");
         customFile.put("feignclient.java", "/templates/api/feignclient.java.btl");
      }
      if (Func.isNotBlank(packageWebDir)) {
         if (Func.equals(codeStyle, SWORD_NAME)) {
            customFile.put("action.js", "/templates/sword/action.js.btl");
            customFile.put("model.js", "/templates/sword/model.js.btl");
            customFile.put("service.js", "/templates/sword/service.js.btl");
            customFile.put("list.js", "/templates/sword/list.js.btl");
            customFile.put("add.js", "/templates/sword/add.js.btl");
            customFile.put("edit.js", "/templates/sword/edit.js.btl");
            customFile.put("view.js", "/templates/sword/view.js.btl");
         } else if (Func.equals(codeStyle, SABER_NAME)) {
            customFile.put("api.js", "/templates/saber/" + templateType + "/api.js.btl");
            customFile.put("const.js", "/templates/saber/" + templateType + "/const.js.btl");
            if (!Func.equals(type, TEMPLATE_SUB)) {
               customFile.put("crud.vue", "/templates/saber/" + templateType + "/crud.vue.btl");
            }
         } else if (Func.equals(codeStyle, ELEMENT_NAME)) {
            customFile.put("api.js", "/templates/element/" + templateType + "/api.js.btl");
            customFile.put("const.js", "/templates/element/" + templateType + "/const.js.btl");
            if (!Func.equals(type, TEMPLATE_SUB)) {
               customFile.put("crud.vue", "/templates/element/" + templateType + "/crud.vue.btl");
            } else {
               customFile.put("sub.vue", "/templates/element/" + templateType + "/sub.vue.btl");
            }
         } else if (Func.equals(codeStyle, LEMON_NAME)) {
            customFile.put("data.ts", "/templates/lemon/" + templateType + "/data.ts.btl");
            customFile.put("Modal.vue", "/templates/lemon/" + templateType + "/Modal.vue.btl");
            customFile.put("data.data.ts", "/templates/lemon/" + templateType + "/data.data.ts.btl");
            if (!Func.equals(type, TEMPLATE_SUB)) {
               customFile.put("index.vue", "/templates/lemon/" + templateType + "/index.vue.btl");
            } else {
               customFile.put("lemonSub.vue", "/templates/lemon/" + templateType + "/sub.vue.btl");
            }
         }
      }
      return customFile;
   }
   private FastAutoGenerator getAutoGenerator(Map<String, Object> customMap, Map<String, String> customFile) {
      Properties props = getProperties();
      String url = Func.toStr(this.url, props.getProperty("spring.datasource.url"));
      String username = Func.toStr(this.username, props.getProperty("spring.datasource.username"));
      String password = Func.toStr(this.password, props.getProperty("spring.datasource.password"));
      return FastAutoGenerator.create(url, username, password)
         .globalConfig(builder -> builder.author(StringUtil.isBlank(author) ? props.getProperty("author") : author).dateType(DateType.TIME_PACK).enableSwagger().outputDir(getOutputDir()).disableOpenDir())
         .packageConfig(builder -> builder.parent(packageName).controller("controller").entity("entity").service("service").serviceImpl("service.impl").mapper("mapper").xml("mapper"))
         .strategyConfig(builder -> builder.addTablePrefix(tablePrefix).addInclude(Func.toStrArray(String.valueOf(customMap.get("modelTable")))).addExclude(excludeTables)
            .entityBuilder().naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel).enableLombok().superClass("org.springblade.core.mp.base.BaseEntity").formatFileName("%sEntity").addSuperEntityColumns(superEntityColumns).enableFileOverride()
            .serviceBuilder().superServiceClass("org.springblade.core.mp.base.BaseService").superServiceImplClass("org.springblade.core.mp.base.BaseServiceImpl").formatServiceFileName("I%sService").formatServiceImplFileName("%sServiceImpl").enableFileOverride()
            .mapperBuilder().mapperAnnotation(Mapper.class).enableBaseResultMap().enableBaseColumnList().formatMapperFileName("%sMapper").formatXmlFileName("%sMapper").enableFileOverride()
            .controllerBuilder().superClass("org.springblade.core.boot.ctrl.BladeController").formatFileName("%sController").enableRestStyle().enableHyphenStyle().enableFileOverride()
         )
         .templateConfig(builder -> builder.disable(TemplateType.ENTITY)
            .entity("/templates/api/entity.java")
            .service("/templates/api/service.java")
            .serviceImpl("/templates/api/serviceImpl.java")
            .mapper("/templates/api/mapper.java")
            .xml("/templates/api/mapper.xml")
            .controller("/templates/api/controller.java"))
         .injectionConfig(builder -> builder.beforeOutputFile(
               (tableInfo, objectMap) -> System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size())
            ).customMap(customMap).customFile(customFile)
         );
   }
   /**
    * èŽ·å–é…ç½®æ–‡ä»¶
    *
    * @return é…ç½®Props
    */
   private Properties getProperties() {
      // è¯»å–配置文件
      Resource resource = new ClassPathResource("/templates/code.properties");
      Properties props = new Properties();
      try {
         props = PropertiesLoaderUtils.loadProperties(resource);
      } catch (IOException e) {
         e.printStackTrace();
      }
      return props;
   }
   /**
    * ç”Ÿæˆåˆ°é¡¹ç›®ä¸­
    *
    * @return outputDir
    */
   public String getOutputDir() {
      return (Func.isBlank(packageDir) ? System.getProperty("user.dir") + "/blade-ops/blade-develop" : packageDir) + "/src/main/java";
   }
   /**
    * ç”Ÿæˆåˆ°Web项目中
    *
    * @return outputDir
    */
   public String getOutputWebDir() {
      return (Func.isBlank(packageWebDir) ? System.getProperty("user.dir") : packageWebDir) + "/src";
   }
}