代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率

#代码生成器配置

#入口类 AutoGenerator

public class AutoGenerator {
    private static final Logger logger = LoggerFactory.getLogger(AutoGenerator.class);

    /**
     * 配置信息
     */
    protected ConfigBuilder config;
    /**
     * 注入配置
     */
    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    protected InjectionConfig injectionConfig;
    /**
     * 数据源配置
     */
    private DataSourceConfig dataSource;
    /**
     * 数据库表配置
     */
    private StrategyConfig strategy;
    /**
     * 包 相关配置
     */
    private PackageConfig packageInfo;
    /**
     * 模板 相关配置
     */
    private TemplateConfig template;
    /**
     * 全局 相关配置
     */
    private GlobalConfig globalConfig;
    /**
     * 模板引擎
     */
    private AbstractTemplateEngine templateEngine;
}

#基本配置

#dataSource

  • 类型:DataSourceConfig
  • 默认值:null

数据源配置,通过该配置,指定需要生成代码的具体数据库,具体请查看 数据源配置

#strategy

  • 类型:StrategyConfig
  • 默认值:null

数据库表配置,通过该配置,可指定需要生成哪些表或者排除哪些表,具体请查看 数据库表配置

#packageInfo

  • 类型:PackageConfig
  • 默认值:null

包名配置,通过该配置,指定生成代码的包路径,具体请查看 包名配置

#template

  • 类型:TemplateConfig
  • 默认值:null

模板配置,可自定义代码生成的模板,实现个性化操作,具体请查看 模板配置

#globalConfig

  • 类型:GlobalConfig
  • 默认值:null

全局策略配置,具体请查看 全局策略配置

#injectionConfig

  • 类型:InjectionConfig
  • 默认值:null

注入配置,通过该配置,可注入自定义参数等操作以实现个性化操作,具体请查看 注入配置

#数据源 dataSourceConfig 配置

#dbQuery

  • 数据库信息查询类
  • 默认由 dbType 类型决定选择对应数据库内置实现

实现 IDbQuery 接口自定义数据库查询 SQL 语句 定制化返回自己需要的内容

#dbType

  • 数据库类型
  • 该类内置了常用的数据库类型【必须】

#schemaName

  • 数据库 schema name
  • 例如 PostgreSQL 可指定为 public

#typeConvert

  • 类型转换
  • 默认由 dbType 类型决定选择对应数据库内置实现

实现 ITypeConvert 接口自定义数据库 字段类型 转换为自己需要的 java 类型,内置转换类型无法满足可实现 IColumnType 接口自定义

#url

  • 驱动连接的URL

#driverName

  • 驱动名称

#username

  • 数据库连接用户名

#password

  • 数据库连接密码

#数据库表配置

#isCapitalMode

是否大写命名

#skipView

是否跳过视图

#naming

数据库表映射到实体的命名策略

#columnNaming

数据库表字段映射到实体的命名策略, 未指定按照 naming 执行

#tablePrefix

表前缀

#fieldPrefix

字段前缀

#superEntityClass

自定义继承的Entity类全称,带包名

#superEntityColumns

自定义基础的Entity类,公共字段

#superMapperClass

自定义继承的Mapper类全称,带包名

#superServiceClass

自定义继承的Service类全称,带包名

#superServiceImplClass

自定义继承的ServiceImpl类全称,带包名

#superControllerClass

自定义继承的Controller类全称,带包名

#enableSqlFilter(since 3.3.1)

默认激活进行sql模糊表名匹配

关闭之后likeTable与notLikeTable将失效,include和exclude将使用内存过滤

如果有sql语法兼容性问题的话,请手动设置为false

已知无法使用:MyCat中间件, 支持情况传送门(opens new window)

#include

需要包含的表名,当enableSqlFilter为false时,允许正则表达式(与exclude二选一配置)

#likeTable

自3.3.0起,模糊匹配表名(与notLikeTable二选一配置)

#exclude

需要排除的表名,当enableSqlFilter为false时,允许正则表达式

#notLikeTable

自3.3.0起,模糊排除表名

#entityColumnConstant

【实体】是否生成字段常量(默认 false)

#entityBuilderModel

【实体】是否为构建者模型(默认 false),自3.3.2开始更名为 chainModel

#chainModel(since 3.3.2)

【实体】是否为链式模型(默认 false)

#entityLombokModel

【实体】是否为lombok模型(默认 false)

3.3.2以下版本默认生成了链式模型,3.3.2以后,默认不生成,如有需要,请开启 chainModel

#entityBooleanColumnRemoveIsPrefix

Boolean类型字段是否移除is前缀(默认 false)

#restControllerStyle

生成 @RestController 控制器

#controllerMappingHyphenStyle

驼峰转连字符

#entityTableFieldAnnotationEnable

是否生成实体时,生成字段注解

#versionFieldName

乐观锁属性名称

#logicDeleteFieldName

逻辑删除属性名称

#tableFillList

表填充字段

#包名配置

#parent

父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名

#moduleName

父包模块名

#entity

Entity包名

#service

Service包名

#serviceImpl

Service Impl包名

#mapper

Mapper包名

#xml

Mapper XML包名

#controller

Controller包名

#pathInfo

路径配置信息

#模板配置

#entity

Java 实体类模板

#entityKt

Kotin 实体类模板

#service

Service 类模板

#serviceImpl

Service impl 实现类模板

#mapper

mapper 模板

#xml

mapper xml 模板

#controller

controller 控制器模板

#全局策略 globalConfig 配置

#outputDir

  • 生成文件的输出目录
  • 默认值:D 盘根目录

#fileOverride

  • 是否覆盖已有文件
  • 默认值:false

#open

  • 是否打开输出目录
  • 默认值:true

#enableCache

  • 是否在xml中添加二级缓存配置
  • 默认值:`false

#author

  • 开发人员
  • 默认值:null

#kotlin

  • 开启 Kotlin 模式
  • 默认值:false

#swagger2

  • 开启 swagger2 模式
  • 默认值:false

#activeRecord

  • 开启 ActiveRecord 模式
  • 默认值:false

#baseResultMap

  • 开启 BaseResultMap
  • 默认值:false

#baseColumnList

  • 开启 baseColumnList
  • 默认值:false

#dateType

  • 时间类型对应策略
  • 默认值:TIME_PACK

注意事项:

如下配置 %s 为占位符

#entityName

  • 实体命名方式
  • 默认值:null 例如:%sEntity 生成 UserEntity

#mapperName

  • mapper 命名方式
  • 默认值:null 例如:%sDao 生成 UserDao

#xmlName

  • Mapper xml 命名方式
  • 默认值:null 例如:%sDao 生成 UserDao.xml

#serviceName

  • service 命名方式
  • 默认值:null 例如:%sBusiness 生成 UserBusiness

#serviceImplName

  • service impl 命名方式
  • 默认值:null 例如:%sBusinessImpl 生成 UserBusinessImpl

#controllerName

  • controller 命名方式
  • 默认值:null 例如:%sAction 生成 UserAction

#idType

  • 指定生成的主键的ID类型
  • 默认值:null

#注入 injectionConfig 配置

#map

  • 自定义返回配置 Map 对象
  • 该对象可以传递到模板引擎通过 cfg.xxx 引用

#fileOutConfigList

  • 自定义输出文件
  • 配置 FileOutConfig 指定模板文件、输出文件达到自定义文件生成目的

#fileCreate

  • 自定义判断是否创建文件
  • 实现 IFileCreate 接口

该配置用于判断某个类是否需要覆盖创建,当然你可以自己实现差异算法 merge 文件

#initMap

  • 注入自定义 Map 对象(注意需要setMap放进去)

源码跟踪分析

开始执行方法

/**
     * 生成代码
     */
    public void execute() {
        logger.debug("==========================准备生成文件...==========================");
        // 初始化配置
        if (null == config) {
            config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
            if (null != injectionConfig) {
                injectionConfig.setConfig(config);
            }
        }
        if (null == templateEngine) {
            // 为了兼容之前逻辑,采用 Velocity 引擎 【 默认 】
            templateEngine = new VelocityTemplateEngine();
        }
        // 模板引擎初始化执行文件输出
        templateEngine.init(this.pretreatmentConfigBuilder(config)).mkdirs().batchOutput().open();
        logger.debug("==========================文件生成完成!!!==========================");
    }
/**
     * 在构造器中处理配置
     *
     * @param packageConfig    包配置
     * @param dataSourceConfig 数据源配置
     * @param strategyConfig   表配置
     * @param template         模板配置
     * @param globalConfig     全局配置
     */
    public ConfigBuilder(PackageConfig packageConfig, DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig,
                         TemplateConfig template, GlobalConfig globalConfig) {
        // 全局配置
        this.globalConfig = Optional.ofNullable(globalConfig).orElseGet(GlobalConfig::new);
        // 模板配置
        this.template = Optional.ofNullable(template).orElseGet(TemplateConfig::new);
        // 包配置
        if (null == packageConfig) {
            handlerPackage(this.template, this.globalConfig.getOutputDir(), new PackageConfig());
        } else {
            handlerPackage(this.template, this.globalConfig.getOutputDir(), packageConfig);
        }
        this.dataSourceConfig = dataSourceConfig;
        this.connection = dataSourceConfig.getConn();
        // 策略配置
        this.strategyConfig = Optional.ofNullable(strategyConfig).orElseGet(StrategyConfig::new);
        this.tableInfoList = getTablesInfo(this.strategyConfig);
    }
/**
     * 处理包配置
     *
     * @param template  TemplateConfig
     * @param outputDir
     * @param config    PackageConfig
     */
    private void handlerPackage(TemplateConfig template, String outputDir, PackageConfig config) {
        // 包信息
        packageInfo = CollectionUtils.newHashMapWithExpectedSize(7);
        packageInfo.put(ConstVal.MODULE_NAME, config.getModuleName());
        packageInfo.put(ConstVal.ENTITY, joinPackage(config.getParent(), config.getEntity()));
        packageInfo.put(ConstVal.MAPPER, joinPackage(config.getParent(), config.getMapper()));
        packageInfo.put(ConstVal.XML, joinPackage(config.getParent(), config.getXml()));
        packageInfo.put(ConstVal.SERVICE, joinPackage(config.getParent(), config.getService()));
        packageInfo.put(ConstVal.SERVICE_IMPL, joinPackage(config.getParent(), config.getServiceImpl()));
        packageInfo.put(ConstVal.CONTROLLER, joinPackage(config.getParent(), config.getController()));

        // 自定义路径
        Map configPathInfo = config.getPathInfo();
        if (null != configPathInfo) {
            pathInfo = configPathInfo;
        } else {
            // 生成路径信息
            pathInfo = CollectionUtils.newHashMapWithExpectedSize(6);
            setPathInfo(pathInfo, template.getEntity(getGlobalConfig().isKotlin()), outputDir, ConstVal.ENTITY_PATH, ConstVal.ENTITY);
            setPathInfo(pathInfo, template.getMapper(), outputDir, ConstVal.MAPPER_PATH, ConstVal.MAPPER);
            setPathInfo(pathInfo, template.getXml(), outputDir, ConstVal.XML_PATH, ConstVal.XML);
            setPathInfo(pathInfo, template.getService(), outputDir, ConstVal.SERVICE_PATH, ConstVal.SERVICE);
            setPathInfo(pathInfo, template.getServiceImpl(), outputDir, ConstVal.SERVICE_IMPL_PATH, ConstVal.SERVICE_IMPL);
            setPathInfo(pathInfo, template.getController(), outputDir, ConstVal.CONTROLLER_PATH, ConstVal.CONTROLLER);
        }
    }
 /**
     * 获取所有的数据库表信息
     */
    private List getTablesInfo(StrategyConfig config) {
        boolean isInclude = config.getInclude().size() > 0;
        boolean isExclude = config.getExclude().size() > 0;
        if (isInclude && isExclude) {
            throw new RuntimeException(" 标签中  只能配置一项!");
        }
        if (config.getNotLikeTable() != null && config.getLikeTable() != null) {
            throw new RuntimeException(" 标签中  只能配置一项!");
        }
        //所有的表信息
        List tableList = new ArrayList<>();

        //需要反向生成或排除的表信息
        List includeTableList = new ArrayList<>();
        List excludeTableList = new ArrayList<>();

        //不存在的表名
        Set notExistTables = new HashSet<>();
        DbType dbType = this.dataSourceConfig.getDbType();
        IDbQuery dbQuery = this.dataSourceConfig.getDbQuery();
        try {
            String tablesSql = dataSourceConfig.getDbQuery().tablesSql();
            if (DbType.POSTGRE_SQL == dbType) {
                String schema = dataSourceConfig.getSchemaName();
                if (schema == null) {
                    //pg 默认 schema=public
                    schema = "public";
                    dataSourceConfig.setSchemaName(schema);
                }
                //TODO 还原代码后解决PgSchema的问题.
                this.connection.setSchema(schema);
                tablesSql = String.format(tablesSql, schema);
            } else if (DbType.KINGBASE_ES == dbType) {
                String schema = dataSourceConfig.getSchemaName();
                if (schema == null) {
                    //kingbase 默认 schema=PUBLIC
                    schema = "PUBLIC";
                    dataSourceConfig.setSchemaName(schema);
                }
                tablesSql = String.format(tablesSql, schema);
            } else if (DbType.DB2 == dbType) {
                String schema = dataSourceConfig.getSchemaName();
                if (schema == null) {
                    //db2 默认 schema=current schema
                    schema = "current schema";
                    dataSourceConfig.setSchemaName(schema);
                }
                tablesSql = String.format(tablesSql, schema);
            }
            //oracle数据库表太多,出现最大游标错误
            else if (DbType.ORACLE == dbType) {
                String schema = dataSourceConfig.getSchemaName();
                //oracle 默认 schema=username
                if (schema == null) {
                    schema = dataSourceConfig.getUsername().toUpperCase();
                    dataSourceConfig.setSchemaName(schema);
                }
                tablesSql = String.format(tablesSql, schema);
            }
            StringBuilder sql = new StringBuilder(tablesSql);
            if (config.isEnableSqlFilter()) {
                if (config.getLikeTable() != null) {
                    sql.append(" AND ").append(dbQuery.tableName()).append(" LIKE '").append(config.getLikeTable().getValue()).append("'");
                } else if (config.getNotLikeTable() != null) {
                    sql.append(" AND ").append(dbQuery.tableName()).append(" NOT LIKE '").append(config.getNotLikeTable().getValue()).append("'");
                }
                if (isInclude) {
                    sql.append(" AND ").append(dbQuery.tableName()).append(" IN (")
                        .append(config.getInclude().stream().map(tb -> "'" + tb + "'").collect(Collectors.joining(","))).append(")");
                } else if (isExclude) {
                    sql.append(" AND ").append(dbQuery.tableName()).append(" NOT IN (")
                        .append(config.getExclude().stream().map(tb -> "'" + tb + "'").collect(Collectors.joining(","))).append(")");
                }
            }
            TableInfo tableInfo;
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
                 ResultSet results = preparedStatement.executeQuery()) {
                while (results.next()) {
                    final String tableName = results.getString(dbQuery.tableName());
                    if (StringUtils.isBlank(tableName)) {
                        System.err.println("当前数据库为空!!!");
                        continue;
                    }
                    tableInfo = new TableInfo();
                    tableInfo.setName(tableName);
                    String commentColumn = dbQuery.tableComment();
                    if (StringUtils.isNotBlank(commentColumn)) {
                        String tableComment = results.getString(commentColumn);
                        if (config.isSkipView() && "VIEW".equals(tableComment)) {
                            // 跳过视图
                            continue;
                        }
                        tableInfo.setComment(formatComment(tableComment));
                    }

                    if (isInclude) {
                        for (String includeTable : config.getInclude()) {
                            // 忽略大小写等于 或 正则 true
                            if (tableNameMatches(includeTable, tableName)) {
                                includeTableList.add(tableInfo);
                            } else {
                                //过滤正则表名
                                if (!REGX.matcher(includeTable).find()) {
                                    notExistTables.add(includeTable);
                                }
                            }
                        }
                    } else if (isExclude) {
                        for (String excludeTable : config.getExclude()) {
                            // 忽略大小写等于 或 正则 true
                            if (tableNameMatches(excludeTable, tableName)) {
                                excludeTableList.add(tableInfo);
                            } else {
                                //过滤正则表名
                                if (!REGX.matcher(excludeTable).find()) {
                                    notExistTables.add(excludeTable);
                                }
                            }
                        }
                    }
                    tableList.add(tableInfo);
                }
            }
            // 将已经存在的表移除,获取配置中数据库不存在的表
            for (TableInfo tabInfo : tableList) {
                notExistTables.remove(tabInfo.getName());
            }
            if (notExistTables.size() > 0) {
                System.err.println("表 " + notExistTables + " 在数据库中不存在!!!");
            }

            // 需要反向生成的表信息
            if (isExclude) {
                tableList.removeAll(excludeTableList);
                includeTableList = tableList;
            }
            if (!isInclude && !isExclude) {
                includeTableList = tableList;
            }
            // 性能优化,只处理需执行表字段 github issues/219
            includeTableList.forEach(ti -> convertTableFields(ti, config));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return processTable(includeTableList, config);
    }

/**
     * 将字段信息与表信息关联
     *
     * @param tableInfo 表信息
     * @param config    命名策略
     * @return ignore
     */
    private TableInfo convertTableFields(TableInfo tableInfo, StrategyConfig config) {
        boolean haveId = false;
        List fieldList = new ArrayList<>();
        List commonFieldList = new ArrayList<>();
        DbType dbType = this.dataSourceConfig.getDbType();
        IDbQuery dbQuery = dataSourceConfig.getDbQuery();
        String tableName = tableInfo.getName();
        try {
            String tableFieldsSql = dbQuery.tableFieldsSql();
            Set h2PkColumns = new HashSet<>();
            if (DbType.POSTGRE_SQL == dbType) {
                tableFieldsSql = String.format(tableFieldsSql, tableName);
            } else if (DbType.KINGBASE_ES == dbType) {
                tableFieldsSql = String.format(tableFieldsSql, dataSourceConfig.getSchemaName(), tableName);
            } else if (DbType.DB2 == dbType) {
                tableFieldsSql = String.format(tableFieldsSql, dataSourceConfig.getSchemaName(), tableName);
            } else if (DbType.ORACLE == dbType) {
                tableName = tableName.toUpperCase();
                tableFieldsSql = String.format(tableFieldsSql.replace("#schema", dataSourceConfig.getSchemaName()), tableName);
            } else if (DbType.DM == dbType) {
                tableName = tableName.toUpperCase();
                tableFieldsSql = String.format(tableFieldsSql, tableName);
            } else if (DbType.H2 == dbType) {
                try (PreparedStatement pkQueryStmt = connection.prepareStatement(String.format(H2Query.PK_QUERY_SQL, tableName));
                     ResultSet pkResults = pkQueryStmt.executeQuery()) {
                    while (pkResults.next()) {
                        String primaryKey = pkResults.getString(dbQuery.fieldKey());
                        if (Boolean.parseBoolean(primaryKey)) {
                            h2PkColumns.add(pkResults.getString(dbQuery.fieldName()));
                        }
                    }
                }
                tableFieldsSql = String.format(tableFieldsSql, tableName);
            } else {
                tableFieldsSql = String.format(tableFieldsSql, tableName);
            }
            try (
                PreparedStatement preparedStatement = connection.prepareStatement(tableFieldsSql);
                ResultSet results = preparedStatement.executeQuery()) {
                while (results.next()) {
                    TableField field = new TableField();
                    String columnName = results.getString(dbQuery.fieldName());
                    // 避免多重主键设置,目前只取第一个找到ID,并放到list中的索引为0的位置
                    boolean isId;
                    if (DbType.H2 == dbType) {
                        isId = h2PkColumns.contains(columnName);
                    } else {
                        String key = results.getString(dbQuery.fieldKey());
                        if (DbType.DB2 == dbType || DbType.SQLITE == dbType) {
                            isId = StringUtils.isNotBlank(key) && "1".equals(key);
                        } else {
                            isId = StringUtils.isNotBlank(key) && "PRI".equals(key.toUpperCase());
                        }
                    }

                    // 处理ID
                    if (isId && !haveId) {
                        haveId = true;
                        field.setKeyFlag(true);
                        tableInfo.setHavePrimaryKey(true);
                        field.setKeyIdentityFlag(dbQuery.isKeyIdentity(results));
                    } else {
                        field.setKeyFlag(false);
                    }
                    // 自定义字段查询
                    String[] fcs = dbQuery.fieldCustom();
                    if (null != fcs) {
                        Map customMap = CollectionUtils.newHashMapWithExpectedSize(fcs.length);
                        for (String fc : fcs) {
                            customMap.put(fc, results.getObject(fc));
                        }
                        field.setCustomMap(customMap);
                    }
                    // 处理其它信息
                    field.setName(columnName);
                    String newColumnName = columnName;
                    IKeyWordsHandler keyWordsHandler = dataSourceConfig.getKeyWordsHandler();
                    if (keyWordsHandler != null && keyWordsHandler.isKeyWords(columnName)) {
                        System.err.printf("当前表[%s]存在字段[%s]为数据库关键字或保留字!%n", tableName, columnName);
                        field.setKeyWords(true);
                        newColumnName = keyWordsHandler.formatColumn(columnName);
                    }
                    field.setColumnName(newColumnName);
                    field.setType(results.getString(dbQuery.fieldType()));
                    INameConvert nameConvert = strategyConfig.getNameConvert();
                    if (null != nameConvert) {
                        field.setPropertyName(nameConvert.propertyNameConvert(field));
                    } else {
                        field.setPropertyName(strategyConfig, processName(field.getName(), config.getColumnNaming()));
                    }
                    field.setColumnType(dataSourceConfig.getTypeConvert().processTypeConvert(globalConfig, field));
                    String fieldCommentColumn = dbQuery.fieldComment();
                    if (StringUtils.isNotBlank(fieldCommentColumn)) {
                        field.setComment(formatComment(results.getString(fieldCommentColumn)));
                    }
                    // 填充逻辑判断
                    List tableFillList = getStrategyConfig().getTableFillList();
                    if (null != tableFillList) {
                        // 忽略大写字段问题
                        tableFillList.stream().filter(tf -> tf.getFieldName().equalsIgnoreCase(field.getName()))
                            .findFirst().ifPresent(tf -> field.setFill(tf.getFieldFill().name()));
                    }
                    if (strategyConfig.includeSuperEntityColumns(field.getName())) {
                        // 跳过公共字段
                        commonFieldList.add(field);
                        continue;
                    }
                    fieldList.add(field);
                }
            }
        } catch (SQLException e) {
            System.err.println("SQL Exception:" + e.getMessage());
        }
        tableInfo.setFields(fieldList);
        tableInfo.setCommonFields(commonFieldList);
        return tableInfo;
    }
/**
     * 处理表对应的类名称
     *
     * @param tableList 表名称
     * @param config    策略配置项
     * @return 补充完整信息后的表
     */
    private List processTable(List tableList, StrategyConfig config) {
        for (TableInfo tableInfo : tableList) {
            String entityName;
            INameConvert nameConvert = strategyConfig.getNameConvert();
            if (null != nameConvert) {
                // 自定义处理实体名称
                entityName = nameConvert.entityNameConvert(tableInfo);
            } else {
                entityName = NamingStrategy.capitalFirst(processName(tableInfo.getName(), config.getNaming(), config.getTablePrefix()));
            }
            if (StringUtils.isNotBlank(globalConfig.getEntityName())) {
                tableInfo.setConvert(true);
                tableInfo.setEntityName(String.format(globalConfig.getEntityName(), entityName));
            } else {
                tableInfo.setEntityName(strategyConfig, entityName);
            }
            if (StringUtils.isNotBlank(globalConfig.getMapperName())) {
                tableInfo.setMapperName(String.format(globalConfig.getMapperName(), entityName));
            } else {
                tableInfo.setMapperName(entityName + ConstVal.MAPPER);
            }
            if (StringUtils.isNotBlank(globalConfig.getXmlName())) {
                tableInfo.setXmlName(String.format(globalConfig.getXmlName(), entityName));
            } else {
                tableInfo.setXmlName(entityName + ConstVal.MAPPER);
            }
            if (StringUtils.isNotBlank(globalConfig.getServiceName())) {
                tableInfo.setServiceName(String.format(globalConfig.getServiceName(), entityName));
            } else {
                tableInfo.setServiceName("I" + entityName + ConstVal.SERVICE);
            }
            if (StringUtils.isNotBlank(globalConfig.getServiceImplName())) {
                tableInfo.setServiceImplName(String.format(globalConfig.getServiceImplName(), entityName));
            } else {
                tableInfo.setServiceImplName(entityName + ConstVal.SERVICE_IMPL);
            }
            if (StringUtils.isNotBlank(globalConfig.getControllerName())) {
                tableInfo.setControllerName(String.format(globalConfig.getControllerName(), entityName));
            } else {
                tableInfo.setControllerName(entityName + ConstVal.CONTROLLER);
            }
            // 检测导入包
            checkImportPackages(tableInfo);
        }
        return tableList;
    }
/**
     * 预处理配置
     *
     * @param config 总配置信息
     * @return 解析数据结果集
     */
    protected ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
        /*
         * 注入自定义配置
         */
        if (null != injectionConfig) {
            injectionConfig.initMap();
            config.setInjectionConfig(injectionConfig);
        }
        /*
         * 表信息列表
         */
        List tableList = this.getAllTableInfoList(config);
        for (TableInfo tableInfo : tableList) {
            /* ---------- 添加导入包 ---------- */
            if (config.getGlobalConfig().isActiveRecord()) {
                // 开启 ActiveRecord 模式
                tableInfo.setImportPackages(Model.class.getCanonicalName());
            }
            if (tableInfo.isConvert()) {
                // 表注解
                tableInfo.setImportPackages(TableName.class.getCanonicalName());
            }
            if (config.getStrategyConfig().getLogicDeleteFieldName() != null && tableInfo.isLogicDelete(config.getStrategyConfig().getLogicDeleteFieldName())) {
                // 逻辑删除注解
                tableInfo.setImportPackages(TableLogic.class.getCanonicalName());
            }
            if (StringUtils.isNotBlank(config.getStrategyConfig().getVersionFieldName())) {
                // 乐观锁注解
                tableInfo.setImportPackages(Version.class.getCanonicalName());
            }
            boolean importSerializable = true;
            if (StringUtils.isNotBlank(config.getStrategyConfig().getSuperEntityClass())) {
                // 父实体
                tableInfo.setImportPackages(config.getStrategyConfig().getSuperEntityClass());
                importSerializable = false;
            }
            if (config.getGlobalConfig().isActiveRecord()) {
                importSerializable = true;
            }
            if (importSerializable) {
                tableInfo.setImportPackages(Serializable.class.getCanonicalName());
            }
            // Boolean类型is前缀处理
            if (config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix()
                && CollectionUtils.isNotEmpty(tableInfo.getFields())) {
                List tableFields = tableInfo.getFields().stream().filter(field -> "boolean".equalsIgnoreCase(field.getPropertyType()))
                    .filter(field -> field.getPropertyName().startsWith("is")).collect(Collectors.toList());
                tableFields.forEach(field -> {
                    //主键为is的情况基本上是不存在的.
                    if (field.isKeyFlag()) {
                        tableInfo.setImportPackages(TableId.class.getCanonicalName());
                    } else {
                        tableInfo.setImportPackages(com.baomidou.mybatisplus.annotation.TableField.class.getCanonicalName());
                    }
                    field.setConvert(true);
                    field.setPropertyName(StringUtils.removePrefixAfterPrefixToLower(field.getPropertyName(), 2));
                });
            }
        }
        return config.setTableInfoList(tableList);
    }
/**
     * 输出 java xml 文件
     */
    public AbstractTemplateEngine batchOutput() {
        try {
            List tableInfoList = getConfigBuilder().getTableInfoList();
            for (TableInfo tableInfo : tableInfoList) {
                Map objectMap = getObjectMap(tableInfo);
                Map pathInfo = getConfigBuilder().getPathInfo();
                TemplateConfig template = getConfigBuilder().getTemplate();
                // 自定义内容
                InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
                if (null != injectionConfig) {
                    injectionConfig.initTableMap(tableInfo);
                    objectMap.put("cfg", injectionConfig.getMap());
                    List focList = injectionConfig.getFileOutConfigList();
                    if (CollectionUtils.isNotEmpty(focList)) {
                        for (FileOutConfig foc : focList) {
                            if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
                                writerFile(objectMap, foc.getTemplatePath(), foc.outputFile(tableInfo));
                            }
                        }
                    }
                }
                // Mp.java
                String entityName = tableInfo.getEntityName();
                if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
                    String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.ENTITY, entityFile)) {
                        writerFile(objectMap, templateFilePath(template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())), entityFile);
                    }
                }
                // MpMapper.java
                if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
                    String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.MAPPER, mapperFile)) {
                        writerFile(objectMap, templateFilePath(template.getMapper()), mapperFile);
                    }
                }
                // MpMapper.xml
                if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
                    String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
                    if (isCreate(FileType.XML, xmlFile)) {
                        writerFile(objectMap, templateFilePath(template.getXml()), xmlFile);
                    }
                }
                // IMpService.java
                if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
                    String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.SERVICE, serviceFile)) {
                        writerFile(objectMap, templateFilePath(template.getService()), serviceFile);
                    }
                }
                // MpServiceImpl.java
                if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
                    String implFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.SERVICE_IMPL, implFile)) {
                        writerFile(objectMap, templateFilePath(template.getServiceImpl()), implFile);
                    }
                }
                // MpController.java
                if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
                    String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.CONTROLLER, controllerFile)) {
                        writerFile(objectMap, templateFilePath(template.getController()), controllerFile);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("无法创建文件,请检查配置信息!", e);
        }
        return this;
    }

自定义新增配置模板

1、在对应的模板路径下新增ftl文件(根据模板引擎类型添加对应的类型文件)

image.png

2、自定义模板路径配置项

/**
 * 自定义模板路径配置项 
 */
@Data
@Accessors(chain = true)
public class CustomFreemarkerTemplateConfig extends TemplateConfig {
    private String dao = "/templates/dao.java";
    private String reactFile = "/templates/react.js";
    private String reactPageFile = "/templates/reactPage.js";
}

3、设置对应模板目录

/**
     * 自定义配置模板
     *
     * @return
     */
    private TemplateConfig initTemplateConfig() {
        CustomFreemarkerTemplateConfig templateConfig = new CustomFreemarkerTemplateConfig();
        String templates = templateProperties.getTemplates();

        if (!StringUtils.isEmpty(templates)) {
            // 配置自定义输出模板
            // 指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
            templateConfig
                    .setController(templateConfig.getController().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig
                    .setEntity(templateConfig.getEntity(false).replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig.setMapper(templateConfig.getMapper().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig.setService(templateConfig.getService().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig
                    .setServiceImpl(templateConfig.getServiceImpl().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig.setXml(templateConfig.getXml().replace(CodeGenerateConstant.TEMPLATES, templates));

            // 自定义 新增模板路径
            templateConfig.setDao(templateConfig.getDao().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig.setReactFile(templateConfig.getReactFile().replace(CodeGenerateConstant.TEMPLATES, templates));
            templateConfig.setReactPageFile(templateConfig.getReactPageFile().replace(CodeGenerateConstant.TEMPLATES, templates));
        }

        return templateConfig;
    }

4、创建对应的模板输出文件配置

/**
 * 自定义生成dao到文件配置
 */
public class DaoFileOutConfig extends FileOutConfig {
    public DaoFileOutConfig() {
    }

    public DaoFileOutConfig(String templatePath) {
        super(templatePath);
    }


    @Override
    public String outputFile(TableInfo tableInfo) {
        String outputDir = ApplicationContextAwareImpl.applicationContext.getBean(GlobalProperties.class).getOutputDir();
        PackageInfoProperties packageInfo = ApplicationContextAwareImpl.applicationContext.getBean(PackageInfoProperties.class);
        String packagePath = packageInfo.getParentPackage() + StringPool.DOT + packageInfo.getModuleName() + StringPool.DOT + "dao";

        // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!

        return joinPath(outputDir, packagePath) + File.separator
                + tableInfo.getEntityName() + "Dao" + StringPool.DOT_JAVA;
    }

    /**
     * 连接路径字符串
     *
     * @param parentDir   路径常量字符串
     * @param packageName 包名
     * @return 连接后的路径
     */
    private String joinPath(String parentDir, String packageName) {
        if (StringUtils.isBlank(parentDir)) {
            parentDir = System.getProperty(ConstVal.JAVA_TMPDIR);
        }
        if (!StringUtils.endsWith(parentDir, File.separator)) {
            parentDir += File.separator;
        }
        packageName = packageName.replaceAll("\\.", StringPool.BACK_SLASH + File.separator);
        return parentDir + packageName;
    }
}

5、自定义注入配置,设置fileOutConfgiList ,

/**
 * 自定义注入配置
 */
public class CustomInjectionConfig extends InjectionConfig {

    public CustomInjectionConfig() {
        this.setFileOutConfigList(initCustomFileOutConfig());
    }

    @Override
    public void initMap() {

    }

    /**
     * 依据表相关信息,从三方获取到需要元数据,处理方法环境里面
     *
     * @param tableInfo
     */
    public void initTableMap(TableInfo tableInfo) {
        // 子类重写注入表对应补充信息
    }

    /**
     * 模板待渲染 Object Map 预处理
* com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine 方法: * getObjectMap 结果处理 */ public Map prepareObjectMap(Map objectMap) { objectMap.put("daoName", objectMap.get("entity") + "Dao"); String entity = (String) objectMap.get("entity"); // 类名首字母小写 objectMap.put("entityName", entity.substring(0, 1).toLowerCase() + entity.substring(1)); objectMap.put("superDaoClassPackage", null); objectMap.put("superDaoClass", null); return objectMap; } /** * 自定义配置 * * @return */ public IFileCreate initFileCreate() { return new IFileCreate() { @Override public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { // 判断自定义文件夹是否需要创建 checkDir("调用默认方法创建的目录,自定义目录用"); if (fileType == FileType.MAPPER) { // 已经生成mapper 文件判断存在,不想重新生成返回 false return !new File(filePath).exists(); } // 允许生成模板文件 return true; } }; } private List initCustomFileOutConfig() { // 自定义输出配置 TemplateProperties templateProperties = ApplicationContextAwareImpl.applicationContext.getBean(TemplateProperties.class); List focList = new ArrayList<>(); if ("erpTemplates".equalsIgnoreCase(templateProperties.getTemplates())) { // 自定义配置会被优先输出 focList.add(new DaoFileOutConfig("/" + templateProperties.getTemplates() + "/dao.java.ftl")); focList.add(new ReactFileOutConfig("/" + templateProperties.getTemplates() + "/react.js.ftl")); focList.add(new ReactPageFileOutConfig("/" + templateProperties.getTemplates() + "/reactPage.js.ftl")); } if ("templates1.0".equalsIgnoreCase(templateProperties.getTemplates())) { } return focList; } }

你可能感兴趣的:(代码生成器)