理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助。但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑时,简单的代码生成功能无法解决。

  目前市面上的代码生成器层出不穷,大多数的原理是基于已有的代码逻辑模板,按照一定的规则来生成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
*/
@Override
protected 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; @Autowired
public void setFieldService(@Lazy IFieldService fieldService) {
this.fieldService = fieldService;
} @Override
public 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;
} @Override
public 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;
} @Override
public 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;
} @Override
public 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()); //dto
String dtoFile = dtoName + CodeGeneratorConstant.DTO_JAVA;
String createDtoFile = CodeGeneratorConstant.CREATE + dtoFile;
String updateDtoFile = CodeGeneratorConstant.UPDATE + dtoFile;
String queryDtoFile = CodeGeneratorConstant.QUERY + dtoFile;
//Export and Import
String exportFile = dtoName + CodeGeneratorConstant.EXPORT_JAVA;
String importFile = dtoName + CodeGeneratorConstant.IMPORT_JAVA;
// SQL
String 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 Import
customFileMap.put(exportFile, CustomFileEnum.EXPORT.path);
customFileMap.put(importFile, CustomFileEnum.IMPORT.path);
// SQL
customFileMap.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))
{
//dto
String 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 Import
String entityPath = serviceCodePath + GitEggCodeGeneratorConstant.JAVA_PATH + codeDirPath + CodeGeneratorConstant.ENTITY;
customFilePath.put(exportFile, entityPath);
customFilePath.put(importFile, entityPath);
// SQL
String 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 js
String 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、代码生成功能运行界面

数据源配置:



代码生成配置:



关联表配置:



表字段配置:



表单配置:



表单校验配置:



列表查询配置:



数据字典配置:



校验规则配置:

源码地址:

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

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

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

  1. SpringCloud微服务实战——搭建企业级开发框架(十一):集成OpenFeign用于微服务间调用

    作为Spring Cloud的子项目之一,Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式,为微服务架构下服务之间的调用提供了解决方案.首先, ...

  2. SpringCloud微服务实战——搭建企业级开发框架(四十三):多租户可配置的电子邮件发送系统设计与实现

      在日常生活中,邮件已经被聊天软件.短信等更便捷的信息传送方式代替.但在日常工作中,我们的重要的信息通知等非常有必要去归档追溯,那么邮件就是不可或缺的信息传送渠道.对于我们工作中经常用到的系统,里面 ...

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

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

  4. SpringCloud微服务实战——搭建企业级开发框架(三十八):搭建ELK日志采集与分析系统

      一套好的日志分析系统可以详细记录系统的运行情况,方便我们定位分析系统性能瓶颈.查找定位系统问题.上一篇说明了日志的多种业务场景以及日志记录的实现方式,那么日志记录下来,相关人员就需要对日志数据进行 ...

  5. SpringCloud微服务实战——搭建企业级开发框架(三十二):代码生成器使用配置说明

    一.新建数据源配置 因考虑到多数据源问题,代码生成器作为一个通用的模块,后续可能会为其他工程生成代码,所以,这里不直接读取系统工程配置的数据源,而是让用户自己维护. 参数说明 数据源名称:用于查找区分 ...

  6. SpringCloud微服务实战——搭建企业级开发框架(二):环境准备

    这里简单说明一下在Windows系统下开发SpringCloud项目所需要的的基本环境,这里只说明开发过程中基础必须的软件,其他扩展功能(Docker,k8s,MinIO,XXL-JOB,EKL,Ke ...

  7. SpringCloud微服务实战——搭建企业级开发框架(五):数据库持久化集成MySql+Druid+MyBatis-Plus

      在引入相关数据库持久化相关依赖库之前,我们可以考虑到,当我们因业务开发需要,引入各种各样的依赖库时,Jar包冲突是我们必须面对的一个问题,Spring为了解决这些Jar包的冲突,推出了各种bom, ...

  8. SpringCloud微服务实战——搭建企业级开发框架(二十三):Gateway+OAuth2+JWT实现微服务统一认证授权

      OAuth2是一个关于授权的开放标准,核心思路是通过各类认证手段(具体什么手段OAuth2不关心)认证用户身份,并颁发token(令牌),使得第三方应用可以使用该token(令牌)在限定时间.限定 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(三十四):SpringCloud + Docker + k8s实现微服务集群打包部署-Maven打包配置

      SpringCloud微服务包含多个SpringBoot可运行的应用程序,在单应用程序下,版本发布时的打包部署还相对简单,当有多个应用程序的微服务发布部署时,原先的单应用程序部署方式就会显得复杂且 ...

随机推荐

  1. Python import urllib2 ImportError: No module named 'urllib2'

    python3 import urllib2 import urllib2 ImportError: No module named 'urllib2' python3.3里面,用urllib.req ...

  2. ES6-变量的解构赋值复习+学习

    ES6------变量的解构赋值 由于之前学过ES6的解构赋值,但是只是略看了一点网上的视频,所以今天就看了看ES6对这一部分的详细介绍,然后做一个总结的笔记. 首先,先大概说一下什么是变量的解构赋值 ...

  3. Allure 生成测试报表

    Allure官方文档参考地址:https://docs.qameta.io/allure/#_testng 1.在maven中添加依赖并进行相应的配置: <!-- 实现版本控制 --> & ...

  4. Java多线程| 01 | 线程概述

    Java多线程| 01 | 线程概述 线程相关概念 进程与线程 进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位.可以把进程简单的理解 ...

  5. 在随着layui官网下架后 layui镜像站起来了

    layui:https://gitee.com/lh_yun/layui 介绍 layui镜像站 「本站仅为 layui 文档保留的镜像站点,与官方无关」 源码地址 在线 pdf 1.主页 https ...

  6. GitHub出现Permission denied (publickey)

    Permission denied (publickey) 没有权限的publickey 重新生成一次ssh key即可解决 ssh-keygen -t rsa -C "这里输入你的邮箱&q ...

  7. [Comet1790]Ternary String Counting

    令$f_{i,j,k}$表示前$i$个位置,三种字符最后一次出现的位置为$i,j$和$k$(保证$k<j<i$)的方案数 考虑转移(递推),即分为两步-- 1.填写第$i$个字符,即从$f ...

  8. 【机器学习基础】卷积神经网络(CNN)基础

    最近几天陆续补充了一些"线性回归"部分内容,这节继续机器学习基础部分,这节主要对CNN的基础进行整理,仅限于基础原理的了解,更复杂的内容和实践放在以后再进行总结. 卷积神经网络的基 ...

  9. [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer

    [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer 目录 [源码解析] PyTorch 分布式(11) ----- Dis ...

  10. AgileConfig-1.5.5 发布 - 支持 JSON 编辑模式

    本次更新加入了2个新的编辑模式:JSON 编辑模式.TEXT 编辑模式.特别是 JSON 编辑模式是大家比较期待的一个功能.因为大家都习惯了 appsettings.json 的配置编辑模式,所以天生 ...