理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助。但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑时,简单的代码生成功能无法解决。
  目前市面上的代码生成器层出不穷,大多数的原理是基于已有的代码逻辑模板,按照一定的规则来生成CRUD代码。至于更为复杂的代码生成大家都在人工智能领域探索,目前基于代码训练的人工智能代码生成还在于提供代码补全功能方面,比如智能编程助手aiXcoder提供了常用IDE插件,在项目开发过程中,可以基于你项目的代码进行训练,编程时提供合适的代码提示。由微软、OpenAI、GitHub 三家联合打造的Copilot 也有异曲同工之妙,都是在项目开发中,提供优秀的代码自动补全功能从而可以提升工作效率。希望在不远的将来,我们可以实现复杂业务逻辑的代码也通过人工智能对大量代码的训练和分析来实现吧。

  这里我们制作的代码生成器,是按照平时开发过程中的思考来设计,一般情况下我们的开发步骤是: 需求分析->数据建模->数据库设计->编写后台代码(增删改查)->编写前台代码(增删改查)->字段校验 ->业务逻辑完善->测试,所以我们希望代码生成器能够:

  • 读取数据库表和字段
  • 根据数据库字段生成实体类和CRUD方法
  • 根据数据库字段生成前端操作页面
  • 前端页面的展示方式可以根据需要配置(form表单、数据展示列表)
  • 可以生成多表联合查询的代码
  • 可以配置字段的校验规则
一、引入依赖的库

1、修改GitEgg-Platform项目中的gitegg-platform-bom工程的pom.xml文件,这里使用mybatis-plus-generator目前最新版本3.5.1来自定义我们需要的代码生成器。

pom.xml

    <properties>......<!-- Mybatis Plus增强工具代码生成 --><mybatis.plus.generator.version>3.5.1</mybatis.plus.generator.version>......</properties><dependencyManagement><dependencies>......<!-- Mybatis Plus代码生成工具 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>${mybatis.plus.generator.version}</version></dependency>......</dependencies></dependencyManagement>

2、在GitEgg-Platform项目中新建gitegg-platform-code-generator工程,提供基本的自定义代码生成能力,以及定义一些常量。

GitEggCodeGeneratorConstant.java常量类

package com.gitegg.platform.code.generator.constant;import java.io.File;/*** @ClassName: GitEggCodeGeneratorConstant * @Description: 常量类* @author GitEgg* @since 2021-10-12*/
public class GitEggCodeGeneratorConstant {/*** CONFIG*/public static final String CONFIG = "config";/*** FIELDS*/public static final String FIELDS = "fields";/*** FORM_FIELDS*/public static final String FORM_FIELDS = "formFields";/*** BASE_ENTITY_FIELD_LIST*/public static final String BASE_ENTITY_FIELD_LIST = "baseEntityFieldList";/*** Author*/public static final String AUTHOR = "GitEgg";/*** JAVA_PATH*/public static final String JAVA_PATH = File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;/*** RESOURCES_PATH*/public static final String RESOURCES_PATH = File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;/*** VUE_PATH*/public static final String VUE_PATH = File.separator + "src" + File.separator + "views" + File.separator;/*** JS_PATH*/public static final String JS_PATH = File.separator + "src" + File.separator + "api" + File.separator;/*** VUE_JS_PATH*/public static final String VUE_JS_PATH = "vueJsPath";/*** CUSTOM_FILE_PATH_MAP*/public static final String CUSTOM_FILE_PATH_MAP = "customFilePathMap";}

3、mybatis-plus-generator3.5.1版本支持生成默认支持生成service、serviceImpl、mapper、mapperXml、controller、entity以及自定的other。这些文件都可以自定义模板和输出路径,但是mybatis-plus-generator是将所有的自定义文件都生成到other定义的目录下面的,这显然不符合我们的需求,比如我们需要的DTO文件,vue文件、js文件都会生成到不同的目录里面去,我们需要自定义扩展FreemarkerTemplateEngine方法,实现自定义文件生成到不同的目录,因为我们使用的是Freemarker所以自定义FreemarkerTemplateEngine这个实现类。

package com.gitegg.platform.code.generator.engine;import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.io.File;
import java.util.Map;/*** Freemarker 自定义输出自定义模板文件** @author GitEgg* @since 2021-10-12*/
public class GitEggFreemarkerTemplateEngine extends FreemarkerTemplateEngine {/*** 自定义输出自定义模板文件** @param customFile 自定义配置模板文件信息* @param tableInfo  表信息* @param objectMap  渲染数据* @since 3.5.1*/@Overrideprotected void outputCustomFile( Map<String, String> customFile, TableInfo tableInfo, Map<String, Object> objectMap) {Map<String, String> customFilePath = (Map<String, String>)objectMap.get("customFilePathMap");customFile.forEach((key, value) -> {String otherPath = customFilePath.get(key);String fileName = String.format((otherPath + File.separator + "%s"), key);outputFile(new File(fileName), objectMap, value);});}
}
二、业务及实现方法

代码生成作为系统的一个功能模块,也需要考虑业务、数据库设计,这里主要有这几个模块:

  • 数据源配置:因为是微服务,可能会有多个数据库,分库分表等,所以这里选择使用配置数据源的方式,在代码生成的时候,让开发人员可以自己选择在哪个数据源下的表进行代码生成。
  • 代码生成基础配置(数据字典):代码生成时用到的组件类型、展示类型等基础配置,都配置的代码生成的数据字典中,这里不使用系统的数据字典。同时,在组件选择时,只可以选择业务的数据字典。
  • 校验规则配置:可以配置字段校验的正则表单式,在字段配置时选择哪些字段进行校验。
  • 代码生成规则配置:数据表配置、联合表配置、字段配置、表单配置、 校验配置、列表配置

1、根据以上业务需求,设计了t_sys_code_generator_datasource(数据源配置)、t_sys_code_generator_config(主数据表配置)、t_sys_code_generator_table_join(联表配置)、t_sys_code_generator_field(表字段配置)、t_sys_code_generator_validate(校验规则配置)、t_sys_code_generator_dict(数据字典配置)共六张表。

CREATE TABLE `t_sys_code_generator_datasource`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`datasource_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据源名称',`url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '连接地址',`username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',`driver` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据库驱动',`db_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据库类型',`comments` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',`del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '数据源配置表' ROW_FORMAT = Dynamic;
CREATE TABLE `t_sys_code_generator_config`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`datasource_id` bigint(20) NULL DEFAULT NULL COMMENT '数据源',`module_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模块名称',`module_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模块代码',`service_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '服务名称',`table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表名',`table_alias` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表别名',`table_prefix` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表前缀',`parent_package` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级包名',`controller_path` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'controller路径',`form_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表单类型 modal弹出框  drawer抽屉  tab新窗口',`table_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表类型 single单表  multi多表',`table_show_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '展示类型 table数据表格 tree_table 树表格 3 left_tree_table左树右表  tree数据树  table_table左表右表  left_table_tree左表右树',`form_item_col` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表单字段排列 1一列一行  2 两列一行',`left_tree_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '左树类型 organization机构树 resource资源权限树 ',`front_code_path` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '前端代码路径',`service_code_path` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '后端代码路径',`import_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否支持导入 1支持 0不支持',`export_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否支持导出 1支持 0不支持',`query_reuse` tinyint(1) NOT NULL DEFAULT 1 COMMENT '查询复用:分页查询和单条记录查询公用同一个sql语句',`status_handling` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态处理',`code_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '代码生成类型  全部  仅后端代码  仅前端代码',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',`del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '代码生成配置表' ROW_FORMAT = Dynamic;
CREATE TABLE `t_sys_code_generator_table_join`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`generation_id` bigint(20) NOT NULL COMMENT '代码生成主键',`datasource_id` bigint(20) NULL DEFAULT NULL COMMENT '数据源和主表一致',`join_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表名',`join_table_alias` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表别名',`join_table_prefix` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表前缀',`join_table_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'left左连接 right右连接 inner等值连接 union联合查询',`join_table_select` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自定义查询字段',`join_table_on` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自定义on条件',`table_sort` int(11) NULL DEFAULT NULL COMMENT '显示排序',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',`del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '多表查询时的联合表配置' ROW_FORMAT = Dynamic;
CREATE TABLE `t_sys_code_generator_field`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`generation_id` bigint(20) NOT NULL COMMENT '代码生成主键',`join_id` bigint(20) NOT NULL COMMENT '关联表主键',`join_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表名',`field_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字段名称',`field_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字段类型',`comment` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字段描述',`entity_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '实体类型',`entity_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '实体名称',`form_add` tinyint(1) NOT NULL DEFAULT 0 COMMENT '表单新增',`form_edit` tinyint(1) NOT NULL DEFAULT 0 COMMENT '表单编辑',`query_term` tinyint(1) NOT NULL DEFAULT 0 COMMENT '查询条件',`list_show` tinyint(1) NOT NULL DEFAULT 0 COMMENT '列表展示',`import_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否支持导入 1支持 0不支持',`export_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否支持导出 1支持 0不支持',`required` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否必填',`field_unique` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否唯一',`query_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询类型',`control_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件类型',`dict_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典编码',`min` bigint(20) NULL DEFAULT NULL COMMENT '最小值',`max` bigint(20) NULL DEFAULT NULL COMMENT '最大值',`min_length` int(11) NOT NULL DEFAULT 0 COMMENT '最小长度',`max_length` int(11) NULL DEFAULT NULL COMMENT '字段最大长度',`default_value` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '默认值',`validate_id` bigint(20) NULL DEFAULT NULL COMMENT '校验规则主键',`validate_regular` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自定义正则表达式校验规则',`field_sort` int(11) NOT NULL DEFAULT 1 COMMENT '显示排序',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',`del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `unique_field`(`generation_id`, `join_id`, `join_table_name`, `field_name`) USING BTREE COMMENT '联合约束'
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字段属性配置表' ROW_FORMAT = Dynamic;
CREATE TABLE `t_sys_code_generator_validate`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`validate_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '校验名称',`validate_regular` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '正则表达式校验规则',`status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '\'0\'禁用,\'1\' 启用',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',`del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字段校验规则配置表' ROW_FORMAT = Dynamic;
CREATE TABLE `t_sys_code_generator_dict`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',`parent_id` bigint(20) NULL DEFAULT NULL COMMENT '字典上级',`ancestors` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所有上级字典id的集合,便于查找',`dict_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典名称',`dict_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典值',`dict_order` int(11) NULL DEFAULT NULL COMMENT '排序',`dict_status` tinyint(2) NULL DEFAULT 1 COMMENT '1有效,0禁用',`comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`creator` bigint(20) NULL DEFAULT NULL COMMENT '创建人',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',`operator` bigint(20) NULL DEFAULT NULL COMMENT '操作人',`del_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '1:删除 0:不删除',PRIMARY KEY (`id`) USING BTREE,INDEX `INDEX_DICT_NAME`(`dict_name`) USING BTREE,INDEX `INDEX_DICT_CODE`(`dict_code`) USING BTREE,INDEX `INDEX_PARENT_ID`(`parent_id`) USING BTREE,INDEX `INDEX_TENANT_ID`(`tenant_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据字典表' ROW_FORMAT = Dynamic;

  表结构建立好之后,先用mybatis-plus-generator默认功能生成基本的CRUD代码,这些CRUD代码就不列出来了,主要说明如何利用mybatis-plus-generator读取数据库表和字段,并结合业务在界面上展示,从而进行代码生成规则的配置。
2、在GitEgg-Cloud项目下,gitegg-plugin子项目下新建gitegg-code-generator工程,新建IEngineService接口和接口实现类EngineServiceImpl用于实现:查询某个数据源的所有表、查询某个表的字段信息、查询某个代码生成配置里面所有的字段配置、执行代码生成功能。

package com.gitegg.code.generator.engine.service;import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.gitegg.code.generator.config.dto.QueryConfigDTO;
import com.gitegg.code.generator.engine.dto.TableDTO;import java.util.List;/*** 代码生成器接口** @author GitEgg*/
public interface IEngineService {/*** 查询某个数据源的所有表** @param queryConfigDTO* @return*/List<TableDTO> queryTableList(QueryConfigDTO queryConfigDTO);/*** 查询某个数据源表的字段信息** @param datasourceId* @param tableNames* @return*/List<TableInfo> queryTableFields(String datasourceId, List<String> tableNames);/*** 查询某个代码生成配置里面所有的字段* @param queryConfigDTO* @return*/List<TableInfo> queryConfigFields(QueryConfigDTO queryConfigDTO);/*** 执行代码生成* @param queryConfigDTO* @return*/boolean processGenerateCode(QueryConfigDTO queryConfigDTO);
}
package com.gitegg.code.generator.engine.service.impl;import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.gitegg.code.generator.config.dto.QueryConfigDTO;
import com.gitegg.code.generator.config.entity.Config;
import com.gitegg.code.generator.config.service.IConfigService;
import com.gitegg.code.generator.datasource.entity.Datasource;
import com.gitegg.code.generator.datasource.service.IDatasourceService;
import com.gitegg.code.generator.engine.GitEggDatabaseQuery;
import com.gitegg.code.generator.engine.constant.CodeGeneratorConstant;
import com.gitegg.code.generator.engine.dto.TableDTO;
import com.gitegg.code.generator.engine.enums.CustomFileEnum;
import com.gitegg.code.generator.engine.service.IEngineService;
import com.gitegg.code.generator.field.dto.FieldDTO;
import com.gitegg.code.generator.field.dto.QueryFieldDTO;
import com.gitegg.code.generator.field.service.IFieldService;
import com.gitegg.code.generator.join.entity.TableJoin;
import com.gitegg.code.generator.join.service.ITableJoinService;
import com.gitegg.platform.base.enums.BaseEntityEnum;
import com.gitegg.platform.code.generator.constant.GitEggCodeGeneratorConstant;
import com.gitegg.platform.code.generator.engine.GitEggFreemarkerTemplateEngine;
import com.gitegg.platform.mybatis.entity.BaseEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** 代码生成器接口类** @author GitEgg*/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class EngineServiceImpl implements IEngineService {private final IConfigService configService;private final IDatasourceService datasourceService;private final ITableJoinService tableJoinService;/*** 解决循环依赖问题*/private IFieldService fieldService;@Autowiredpublic void setFieldService(@Lazy IFieldService fieldService) {this.fieldService = fieldService;}@Overridepublic List<TableDTO> queryTableList(QueryConfigDTO queryConfigDTO) {Datasource datasource = datasourceService.getById(queryConfigDTO.getDatasourceId());DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(datasource.getUrl(), datasource.getUsername(), datasource.getPassword()).build();ConfigBuilder configBuilder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null);List<TableDTO> tableInfos = (new GitEggDatabaseQuery(configBuilder)).queryDatasourceTables();return tableInfos;}@Overridepublic List<TableInfo> queryTableFields(String datasourceId, List<String> tableNames) {Datasource datasource = datasourceService.getById(datasourceId);DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(datasource.getUrl(), datasource.getUsername(), datasource.getPassword()).build();//设置有哪些表StrategyConfig strategyConfig = new StrategyConfig.Builder().addInclude(tableNames.toArray(new String[]{})).entityBuilder().enableChainModel().enableLombok().enableRemoveIsPrefix().enableTableFieldAnnotation().enableActiveRecord().logicDeleteColumnName(BaseEntityEnum.DEL_FLAG.field).logicDeletePropertyName(BaseEntityEnum.DEL_FLAG.entity).naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel).addTableFills(new Column(BaseEntityEnum.CREATE_TIME.field, FieldFill.INSERT)).addTableFills(new Column(BaseEntityEnum.UPDATE_TIME.field, FieldFill.INSERT_UPDATE)).idType(IdType.AUTO).build();ConfigBuilder configBuilder = new ConfigBuilder(null, dataSourceConfig, strategyConfig, null, null, null);List<TableInfo> tableInfoList = configBuilder.getTableInfoList();return tableInfoList;}@Overridepublic List<TableInfo> queryConfigFields(QueryConfigDTO queryConfigDTO) {List<String> tableNames = new ArrayList<>();String tableName = queryConfigDTO.getTableName();tableNames.add(tableName);Long id = queryConfigDTO.getId();// 查询是否有联表if (CodeGeneratorConstant.TABLE_DATA_TYPE_MULTI.equals(queryConfigDTO.getTableType())){QueryWrapper<TableJoin> queryWrapper = new QueryWrapper<>();queryWrapper.eq(CodeGeneratorConstant.GENERATION_ID, id);List<TableJoin> tableJoinList = tableJoinService.list(queryWrapper);if(!CollectionUtils.isEmpty(tableJoinList)){tableJoinList.stream().forEach(tableJoin->{tableNames.add(tableJoin.getJoinTableName());});}}Datasource datasource = datasourceService.getById(queryConfigDTO.getDatasourceId());DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(datasource.getUrl(), datasource.getUsername(), datasource.getPassword()).build();//设置有哪些表StrategyConfig strategyConfig = new StrategyConfig.Builder().addInclude(tableNames.toArray(new String[]{})).build();ConfigBuilder configBuilder = new ConfigBuilder(null, dataSourceConfig, strategyConfig, null, null, null);List<TableInfo> tableInfoList = configBuilder.getTableInfoList();return tableInfoList;}@Overridepublic boolean processGenerateCode(QueryConfigDTO queryConfigDTO){Config config = configService.getById(queryConfigDTO.getId());QueryFieldDTO queryFieldDTO = new QueryFieldDTO();queryFieldDTO.setGenerationId(queryConfigDTO.getId());List<FieldDTO> fieldDTOS = fieldService.queryFieldList(queryFieldDTO);//提取表单的字段List<FieldDTO> formFieldDTOS = fieldDTOS.stream().filter(f->f.getFormAdd() || f.getFormEdit()).collect(Collectors.toList());Map<String, Object> customMap = new HashMap<>();customMap.put(GitEggCodeGeneratorConstant.CONFIG, config);customMap.put(GitEggCodeGeneratorConstant.FIELDS, fieldDTOS);customMap.put(GitEggCodeGeneratorConstant.FORM_FIELDS, formFieldDTOS);//baseEntity里面有的,DTO中需要排除的字段List<String> baseEntityFieldList = BaseEntityEnum.getBaseEntityFieldList();customMap.put(GitEggCodeGeneratorConstant.BASE_ENTITY_FIELD_LIST, baseEntityFieldList);//查询数据源配置Datasource datasource = datasourceService.getById(config.getDatasourceId());String serviceName = config.getServiceName();//前端代码路径String frontCodePath = config.getFrontCodePath();//后端代码路径String serviceCodePath = config.getServiceCodePath();//自定义路径String parent = config.getParentPackage();String moduleName = config.getModuleCode();String codeDirPath =  (parent + StrUtil.DOT + moduleName).replace(StrUtil.DOT, File.separator) + File.separator;FastAutoGenerator.create(datasource.getUrl(), datasource.getUsername(), datasource.getPassword()).globalConfig(builder -> {//全局配置String author = GitEggCodeGeneratorConstant.AUTHOR;builder.author(author) // 设置作者.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.disableOpenDir().outputDir(serviceCodePath + GitEggCodeGeneratorConstant.JAVA_PATH); // 指定输出目录}).packageConfig(builder -> {//包配置Map<OutputFile, String> pathInfoMap = new HashMap<>();pathInfoMap.put(OutputFile.mapperXml, serviceCodePath + GitEggCodeGeneratorConstant.RESOURCES_PATH + codeDirPath + CodeGeneratorConstant.MAPPER);builder.parent(parent) // 设置父包名.moduleName(moduleName) // 设置父包模块名.pathInfo(pathInfoMap); // 自定义生成路径}).injectionConfig(builder -> {String dtoName = StrUtil.upperFirst(config.getModuleCode());//dtoString dtoFile = dtoName + CodeGeneratorConstant.DTO_JAVA;String createDtoFile = CodeGeneratorConstant.CREATE + dtoFile;String updateDtoFile = CodeGeneratorConstant.UPDATE + dtoFile;String queryDtoFile = CodeGeneratorConstant.QUERY + dtoFile;//Export and ImportString exportFile = dtoName + CodeGeneratorConstant.EXPORT_JAVA;String importFile = dtoName + CodeGeneratorConstant.IMPORT_JAVA;// SQLString sqlFile = dtoName + CodeGeneratorConstant.RESOURCE_SQL;// 设置自定义输出文件Map<String, String> customFileMap = new HashMap<>();customFileMap.put(dtoFile, CustomFileEnum.DTO_FILE.path);customFileMap.put(createDtoFile, CustomFileEnum.CREATE_DTO.path);customFileMap.put(updateDtoFile, CustomFileEnum.UPDATE_DTO.path);customFileMap.put(queryDtoFile, CustomFileEnum.QUERY_DTO.path);// Export and ImportcustomFileMap.put(exportFile, CustomFileEnum.EXPORT.path);customFileMap.put(importFile, CustomFileEnum.IMPORT.path);// SQLcustomFileMap.put(sqlFile, CustomFileEnum.SQL.path);//因为目前版本框架只支持自定义输出到other目录,所以这里利用重写AbstractTemplateEngine的outputCustomFile方法支持所有自定义文件输出目录Map<String, String> customFilePath = new HashMap<>();int start = serviceName.indexOf(StrUtil.DASHED);int end = serviceName.length();String servicePath = serviceName.substring(start, end).replace(StrUtil.DASHED, File.separator);//判断是否生成后端代码if (config.getCodeType().equals(CodeGeneratorConstant.CODE_ALL) || config.getCodeType().equals(CodeGeneratorConstant.CODE_SERVICE)){//dtoString dtoPath = serviceCodePath + GitEggCodeGeneratorConstant.JAVA_PATH + codeDirPath + CodeGeneratorConstant.DTO;customFilePath.put(dtoFile, dtoPath);customFilePath.put(createDtoFile, dtoPath);customFilePath.put(updateDtoFile, dtoPath);customFilePath.put(queryDtoFile, dtoPath);// Export and ImportString entityPath = serviceCodePath + GitEggCodeGeneratorConstant.JAVA_PATH + codeDirPath + CodeGeneratorConstant.ENTITY;customFilePath.put(exportFile, entityPath);customFilePath.put(importFile, entityPath);// SQLString sqlPath = serviceCodePath + GitEggCodeGeneratorConstant.RESOURCES_PATH + codeDirPath + CodeGeneratorConstant.MAPPER;customFilePath.put(sqlFile, sqlPath);}//判断是否生成后端代码if (config.getCodeType().equals(CodeGeneratorConstant.CODE_ALL) || config.getCodeType().equals(CodeGeneratorConstant.CODE_FRONT)){// vue and jsString vueFile = config.getModuleCode() + CodeGeneratorConstant.TABLE_VUE;String jsFile = config.getModuleCode() + CodeGeneratorConstant.JS;String vuePath = frontCodePath + GitEggCodeGeneratorConstant.VUE_PATH + servicePath + File.separator + config.getModuleCode();String jsPath = frontCodePath + GitEggCodeGeneratorConstant.JS_PATH + servicePath + File.separator + config.getModuleCode();customFilePath.put(vueFile, vuePath);customFilePath.put(jsFile, jsPath);// VUE AND JS// TODO 要支持树形表、左树右表、左表右表、左表右树、左树右树形表、左树右树customFileMap.put(vueFile, CustomFileEnum.VUE.path);customFileMap.put(jsFile, CustomFileEnum.JS.path);customMap.put(GitEggCodeGeneratorConstant.VUE_JS_PATH, servicePath.replace(File.separator, StrUtil.SLASH) + StrUtil.SLASH + config.getModuleCode() + StrUtil.SLASH + config.getModuleCode());}customMap.put(GitEggCodeGeneratorConstant.CUSTOM_FILE_PATH_MAP, customFilePath);builder.customMap(customMap).customFile(customFileMap);}).strategyConfig(builder -> {builder.addInclude(config.getTableName()).addTablePrefix(config.getTablePrefix()).entityBuilder().enableLombok().enableTableFieldAnnotation() // 实体字段注解.superClass(BaseEntity.class).addSuperEntityColumns(BaseEntityEnum.TENANT_ID.field, BaseEntityEnum.CREATE_TIME.field,BaseEntityEnum.CREATOR.field, BaseEntityEnum.UPDATE_TIME.field, BaseEntityEnum.OPERATOR.field, BaseEntityEnum.DEL_FLAG.field).naming(NamingStrategy.underline_to_camel).addTableFills(new Column(BaseEntityEnum.CREATE_TIME.field, FieldFill.INSERT))  //基于数据库字段填充.addTableFills(new Column(BaseEntityEnum.UPDATE_TIME.field, FieldFill.INSERT_UPDATE))    //基于模型属性填充.controllerBuilder().enableRestStyle().enableHyphenStyle().mapperBuilder()
//                            .enableMapperAnnotation().enableBaseResultMap().enableBaseColumnList();}).templateConfig(builder -> {if (config.getCodeType().equals(CodeGeneratorConstant.CODE_FRONT)) {builder.disable();}})// 使用Freemarker引擎模板,默认的是Velocity引擎模板.templateEngine(new GitEggFreemarkerTemplateEngine()).execute();return true;}
}

3、修改代码生成的模板文件,因为默认的代码模板生成文件不能满足我们的需求,我们需要新增DTO、vue、js、数据导入导出实体定义类等模板,在模板接口新增导入导出等方法,在DTO添加字段校验等。因为模板代码太多,这里不详细列举,可以在在GitHub 或者 Gitee下载查看。
4、代码生成功能运行界面

数据源配置:

代码生成配置:

关联表配置:

表字段配置:

表单配置:

表单校验配置:

列表查询配置:

数据字典配置:

校验规则配置:

GitEgg-Cloud是一款基于SpringCloud整合搭建的企业级微服务应用开发框架,开源项目地址:

Gitee: https://gitee.com/wmz1930/GitEgg
GitHub: https://github.com/wmz1930/GitEgg

欢迎感兴趣的小伙伴Star支持一下。

SpringCloud微服务实战——搭建企业级开发框架(三十一):自定义MybatisPlus代码生成器实现前后端代码自动生成相关推荐

  1. SpringCloud微服务实战——搭建企业级开发框架(四十一):扩展JustAuth+SpringSecurity+Vue实现多租户系统微信扫码、钉钉扫码等第三方登录

      前面我们详细介绍了SSO.OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端.目前很多平台都提供了单 ...

  2. SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表

      读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能.也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器:第二台数据库服务器,主要进行读的操作.   目前有多种方式实现读写分 ...

  3. SpringCloud微服务实战——搭建企业级开发框架(四十八):【移动开发】整合uni-app搭建移动端快速开发框架-使用第三方UI框架

     uni-app默认使用uni-ui全端兼容的.高性能UI框架,在我们开发过程中可以满足大部分的需求了,并且如果是为了兼容性,还是强烈建议使用uni-ui作为UI框架使用.   如果作为初创公司,自身 ...

  4. springcloud微服务实战 学习笔记五 Hystrix服务降级 Hystrix依赖隔离 断路器

    ###服务降级 在之前eureka-consumer的基础上 添加依赖 <dependency><groupId>org.springframework.cloud</g ...

  5. SpringCloud微服务实战(四)-微服务中的服务拆分

    订单服务源码 https://github.com/Wasabi1234/SpringCloud_OrderDemo 商品服务源码 https://github.com/Wasabi1234/Spri ...

  6. springcloud微服务实战--笔记--1、基础知识

    微服务的问题: 分布式事务和数据一致性. 由于分布式事务本身第实现难度就非常大,所以在微服务架构中,我们更强调在各服务之间进行无事务第调用,而对于数据一致性,只要求数据在最后第处理状态是一致第即可:若 ...

  7. SpringCloud微服务实战(一)-简介

  8. 分布式与微服务——Iaas,Paas和Saas、单体应用和缺点、微服务概念、传统 分布式 SOA 架构与微服务架构的区别、微服务实战、什么是RPC、CAP定理和BASE理论、唯一ID生成、实现分布式

    文章目录 1-什么是Iaas,Paas和Saas 一 IaaS基础设施服务 二 paas平台即服务 三saas软件即服务 四 总结 2-单体应用和缺点 一 单体应用 二 单体应用的缺陷 3-微服务概念 ...

  9. Django 快速搭建博客 第十一节(文章阅读量统计,自动生成文章摘要)

    这一节主要做一些修补工作,一个是:文章阅读量的统计,另一个是自动生成文章摘要内容 1 . 文章阅读量的统计: 1 文章阅读量的统计,我们需要在model下的Post类中新加入一个views 字段用来统 ...

最新文章

  1. 每天一个linux命令(48):watch命令
  2. 基于 tcp协议完成的上传下载
  3. win7系统怎么查看服务器IP地址,win7系统的ip地址在哪 小编教你怎么查看
  4. 带进度的文件复制 - 回复 冷风无泪 的问题
  5. nyoj--79--导弹拦截(动态规划)
  6. bzoj 2905 背单词
  7. 调用Microsoft.Jet.OLEDB.4.0需要MDAC2.7支持
  8. PHP 数据库连接池实现(转)
  9. Matplotlib 中文用户指南 3.8 路径教程
  10. 闲鱼发布2020租房报告:每天近万人在闲鱼找室友
  11. 3D建模设计软件Rhino 7 for Mac
  12. git 小札 - 流程总览
  13. 项目六 AR与减速机应用
  14. 东莞芯钰科运动控制卡实战记录-硬件篇
  15. CDA Day1-3 Excel公式常用函数跟课学习
  16. 数澜、宜信、贝壳三种数据中台建设模式探讨 | 数澜科技
  17. 成龙坦言演蒲松龄曾打退堂鼓:我演大文豪谁信啊
  18. python实现模糊综合评判
  19. 艾拉物联:标准协议不同,碎片化将是IoT长期挑战
  20. YOLO-先验框/anchor(锚点)

热门文章

  1. Java中setyear和getyear_java时间类Calander,Date等的问题
  2. php+ajax实现分页
  3. ng-include
  4. 百城百店 宝瓷林.北京SKP商场品牌店开业
  5. Live555本地保存H264/PCM视频音频帧附加SPS/PPS
  6. 高德地图自定义地图怎么去除最上边这个默认的蓝色天空?太丑了!!
  7. ViewFlipper-仿淘宝垂直广告滚动
  8. 2019年春节春晚红包大战战报!30亿!
  9. 20行Python代码爬取网站美女图,哇太多了,我U盘装满了
  10. CRM管理系统查询客户信息