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文件(根据模板引擎类型添加对应的类型文件)
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;
}
}