一、背景说明:
在项目研发过程中,通过自动化工具生成ORM对象关系映射是一件必不可少的工作。
mybatis plus generator 是一个很好用的工具,在新搭建的项目中研发兄弟尝新,使用了 generator 的3.5.1 和3.5.2 版本,在生成自带的基础工具类的基础上,想再同时生成相应的 PO、VO、DTO和转换工具等实体,发现3.5.1以上关于自定义定制类资料较少,因故写此文章,记录研学结果。希望对大家有用
二、mybatis plus generator jar 包引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
三、开发环境简单介绍
mac 、jdk 1.8 、idea 、mysql 、使用 Velocity 模板自定义生成工具类(默认)
四、基础配置使用说明
1、基础路径信息配置
/**数据库链接地址**/
private static final String JDBC_URL_MAN = "jdbc:mysql://127.0.0.1:3306/myDatabase?useUnicode=true&characterEncoding=UTF-8";
/**数据库登录账号**/
private static final String JDBC_UserName = "root";
/**数据库登录密码**/
private static final String JDBC_Password = "root1234";
/**
* 【需要修改】
* 需要进行生成文件的表名
* 多张表,表名间使用,号分割
**/
private static final String[] Tables = { "user_table"};
/**
* 【需要修改】
* 生成类的注释
* 作者名称
*/
private static final String CODE_AUTHOR = "timerbin";
/**
* 生成的文件存放地址 之
* 文件路径
*/
private static final String FILE_STORAGE_FILE_ROOT_PATH = System.getProperty("user.dir")+"/user-obj/user-obj-dao/src/test/java/";
/**
* 生成的文件存放地址 之
* 父级 jar包路径
*/
private static final String FILE_STORAGE_FILE_JAR_PACKAGE = "com.jd.timer.bin.user.dao";
/**
*
* 生成的文件存放地址 之
* 模块 jar包名称
*/
private static final String FILE_STORAGE_FILE_JAR_PACKAGE_MODULE = "build";
/**
* 生成的文件存放地址 之
* Service 接口 存放地址
*/
private static final String FILE_STORAGE_SERVICE_FILE_JAR_PACKAGE= "service";
/**
* 生成的文件存放地址 之
* Service impl 实现类 存放地址
*/
private static final String FILE_STORAGE_SERVICE_IMPL_FILE_JAR_PACKAGE= "impl";
/**
* 生成的文件存放地址 之
* entity 实体类 存放地址
*/
private static final String FILE_STORAGE_ENTITY_FILE_JAR_PACKAGE= "entity";
/**
* 生成的文件存放地址 之
* mapper 操作类 存放地址
*/
private static final String FILE_STORAGE_MAPPER_FILE_JAR_PACKAGE= "mapper";
/**
* 生成的文件存放地址 之
* mapper xml 文件 存放地址
*/
private static final String FILE_STORAGE_MAPPER_XML_FILE_JAR_PACKAGE= "mapper";
/**
* 自定义 、定制 生成的文件存放地址 之
* other 其他文件 存放地址
*/
private static final String FILE_STORAGE_OTHER_FILE_JAR_PACKAGE= "other";
以上配置主要目的是指定数据库、表,以及生成的基础文件存放路径,此处无需多关注,且朝下看
2、自动生成工具 main 方法
public static void main(String[] args) {
//设置数据库信息
/***
* 数据库信息配置
*/
DataSourceConfig dataSourceConfig = configDataSource();
/**
* 生成工具类
**/
AutoGenerator generator = new AutoGenerator(dataSourceConfig);
/**
* 全局变量配置
*/
generator.global(configGlobel());
/**
* 设置生成文件包名地址
*/
generator.packageInfo(configPackage());
/**
* 生成文件的策略配置
*/
generator.strategy(configStratgy());
/**
* 生成的类的模板配置
*/
generator.template(configTemplate());
/**
* 自定义实体信息
**/
generator.injection(initInjectionConfig());
/**
* 自定义模板解析器
*/
YaoVelocityTemplateEngine yaoVelocityTemplateEngine = new YaoVelocityTemplateEngine();
generator.execute(yaoVelocityTemplateEngine);
}
相关jar 包引用
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
3、关键各个子方法
/**
* 配置基础转换器
* @return
*/
private static DataSourceConfig configDataSource() {
/**数据库链接配置**/
DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(
JDBC_URL_MAN,
JDBC_UserName,
JDBC_Password
)
.dbQuery(new MySqlQuery())
/**自定义转换器,将tinyint 转换为Integer**/
.typeConvert(new EasyMySqlTypeConvert())
.keyWordsHandler(new MySqlKeyWordsHandler())
.build();
return dataSourceConfig;
}
/**
* 自定义转换器转换器 内部类
* 目的将数据库表中定义的 tinyint 或 bit类型转变为 java Integer 类型
* @author timerbin
*/
static class EasyMySqlTypeConvert extends MySqlTypeConvert {
@Override
public IColumnType processTypeConvert(GlobalConfig config, String fieldType) {
IColumnType iColumnType = super.processTypeConvert(config, fieldType);
if (fieldType.equals("tinyint(1)")) {
iColumnType = DbColumnType.INTEGER;
}
if (fieldType.equals("bit(1)")) {
iColumnType = DbColumnType.BYTE;
}
return iColumnType;
}
}
/**
* 设置全局变量
* @return
*/
private static GlobalConfig configGlobel() {
GlobalConfig globalConfig = new GlobalConfig.Builder()
.fileOverride()
.disableOpenDir()
/**存放生成文件的文件夹地址**/
.outputDir(FILE_STORAGE_FILE_ROOT_PATH)
.author(CODE_AUTHOR)
.dateType(DateType.ONLY_DATE)
.commentDate("yyyy-MM-dd hh:mm:ss")
.build();
return globalConfig;
}
/**
* 生成文件存储目录配置
* @return
*/
private static PackageConfig configPackage() {
PackageConfig packageConfig = new PackageConfig.Builder()
/**存放生成文件的 父级 package 地址**/
.parent(FILE_STORAGE_FILE_JAR_PACKAGE)
/**存放生成文件的 的 父级模块地址**/
.moduleName(FILE_STORAGE_FILE_JAR_PACKAGE_MODULE)
/**存放生成文件的 service 接口 存放的package地址**/
.service(FILE_STORAGE_SERVICE_FILE_JAR_PACKAGE)
/**存放生成文件的 service 接口实现类 存放的package地址**/
.serviceImpl(FILE_STORAGE_SERVICE_IMPL_FILE_JAR_PACKAGE)
/**存放生成文件的 实体类 存放的package地址**/
.entity(FILE_STORAGE_ENTITY_FILE_JAR_PACKAGE)
/**存放生成文件的 mapper 操作类 存放的package地址**/
.mapper(FILE_STORAGE_MAPPER_FILE_JAR_PACKAGE)
/**存放生成文件的 mapper 操作类 xml 存放的package地址**/
.xml(FILE_STORAGE_MAPPER_XML_FILE_JAR_PACKAGE)
/**存放生成文件的 其他实体类 存放的package地址**/
.other(FILE_STORAGE_OTHER_FILE_JAR_PACKAGE)
.build();
return packageConfig;
}
/**
* 生成文件的策略配置
* @return
*/
private static StrategyConfig configStratgy() {
/**
* 初始化配置
* 策略中实体字段的默认填充装置
*
*/
List<IFill> tableFillList = makeInitTableFills();
StrategyConfig strategyConfig = new StrategyConfig.Builder()
.addInclude(Tables)
.entityBuilder()//开始定制实体
/***禁用生成 serialVersionUID**/
// .disableSerialVersionUID()
.enableActiveRecord()
.enableLombok()
.enableRemoveIsPrefix()
.enableTableFieldAnnotation()
.enableChainModel()
.naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel)
/***逻辑删除字段名(数据库)**/
// .logicDeleteColumnName("yn")
.addTableFills(tableFillList)
.idType(IdType.AUTO)
/**格式化实体类文件名称***/
//.formatFileName("%sEntity")
.serviceBuilder()//开始定制Service,由于我们不需要service此处略
/***格式化 service 接口文件名称**/
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.mapperBuilder()//开始定制映射器
.enableMapperAnnotation()
.superClass(BaseMapper.class)
.enableBaseColumnList()
.enableBaseResultMap()
.formatMapperFileName("%sMapper")
.formatXmlFileName("%sMapper")
.build();
return strategyConfig;
}
/**
* 类生成策略
* 配置字段默认填充装置
*
* @return
*/
private static List<IFill> makeInitTableFills(){
List<IFill> tableFillList = new ArrayList<>();
/**定义创建时间 插入时默认填充**/
Column createTableFill = new Column("created", FieldFill.INSERT);
/** 定义修改时间 插入或修改时默认填充**/
Column updateTableFill = new Column("modified", FieldFill.INSERT_UPDATE);
tableFillList.add(createTableFill);
tableFillList.add(updateTableFill);
return tableFillList;
}
/**
* 设置其他模板
* @return
*/
private static TemplateConfig configTemplate() {
TemplateConfig templateConfig = new TemplateConfig.Builder()
.controller(null)//我不需要controller 此处传null
.service(null)//我不需要service 此处传null
.serviceImpl(null)//我不需要service impl 此处传null
.build();
return templateConfig;
}
/**
*
* @return
*/
private static InjectionConfig initInjectionConfig(){
/**自定义生成模板参数**/
Map<String,Object> paramMap = new HashMap<>();
/** 自定义 生成类**/
Map<String,String> customFileMap = new HashMap<>();
/**PO实体**/
customFileMap.put("po"+File.separator+"%sPO.java", "/templates/PO.java.vm");
/**Vo实体**/
customFileMap.put("vo"+File.separator+"%sVO.java", "/templates/VO.java.vm");
/**DTO实体**/
customFileMap.put("dto"+File.separator+"%sDTO.java", "/templates/DTO.java.vm");
return new InjectionConfig.Builder()
.customMap(paramMap)
.customFile(customFileMap)
.build();
}
以上为配置大多数为mybatis plus generator 3.5.1 的基础配置,网上相关说明资料较多,这里不做过多赘述,以下文章写的较全,大家可以借鉴下。
详见:mybatis-plus代码生成器及配置 - BlogMemory - 博客园
五、着重说明-自定义、定制工具类
1、主要配置方法在以上代码中已列出,为 initInjectionConfig() 方法,需同步配置信息
//1、指定生成的自定文件存放路径
/**存放生成文件的 其他实体类 存放的package地址**/
new PackageConfig.Builder().other(FILE_STORAGE_OTHER_FILE_JAR_PACKAGE);
//2、自定义重新生成自定义、定制类的工具
/**
* 自定义模板解析器
*/
TimerVelocityTemplateEngine timerVelocityTemplateEngine = new TimerVelocityTemplateEngine();
//3、定义注入配置方法
/**
* 自定义注入配置
* @return
*/
private static InjectionConfig initInjectionConfig(){
/**自定义生成模板参数**/
Map<String,Object> paramMap = new HashMap<>();
/** 自定义 生成类**/
Map<String,String> customFileMap = new HashMap<>();
/**PO实体**/
customFileMap.put("po"+File.separator+"%sPO.java", "/templates/PO.java.vm");
/**Vo实体**/
customFileMap.put("vo"+File.separator+"%sVO.java", "/templates/VO.java.vm");
/**DTO实体**/
customFileMap.put("dto"+File.separator+"%sDTO.java", "/templates/DTO.java.vm");
return new InjectionConfig.Builder()
.customMap(paramMap)
.customFile(customFileMap)
.build();
}
//4、将自定义注入配置放入到 自动工具生成器中
/**
* 自定义实体信息
**/
generator.injection(initInjectionConfig());
//开始执行基础类生成
generator.execute(timerVelocityTemplateEngine);
2、重点说一下 InjectionConfig 注入配置的属性
方法 | 说明 | 作用 |
beforeOutputFile(BiConsumer<TableInfo, Map<String, Object>>) | 输出文件之前消费者 | |
customMap(Map<String, Object>) | 自定义配置 Map 对象 key:传入参数的名称 value : 传入参数的对象 |
向自定义模板中传入参数和值 |
customFile(Map<String, String>) | 自定义配置模板文件Map key:用于定义生成自定义、定制类的名称 value:用于指定自定义、定制类的模板地址,默认为Velocity模板 |
自定义模板名称和模板 |
3、详细说明一下 重写的 YaoVelocityTemplateEngine 类
重写后代码:
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.jd.jsf.gd.util.JsonUtils;
public class TimerVelocityTemplateEngine extends VelocityTemplateEngine {
@Override
protected void outputCustomFile( Map<String, String> customFile, TableInfo tableInfo,Map<String, Object> objectMap) {
//数据库表映射实体名称
String entityName = tableInfo.getEntityName();
String otherPath = this.getPathInfo(OutputFile.other);
//System.out.println(JsonUtils.toJSONString(tableInfo));
//数据库表映射实体名称 驼峰命名法
objectMap.put("humpEentityName",toLowerCaseFirstOne(entityName));
customFile.forEach((key, value) -> {
String fileName = String.format(otherPath + File.separator +key,entityName);
this.outputFile(new File(fileName), objectMap, value);
});
}
/**
* 首字母转为小写
* @param s
* @return
*/
private String toLowerCaseFirstOne(String s){
if(Character.isLowerCase(s.charAt(0))) {
return s;
}else {
return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
}
}
}
重写前源码:
//AbstractTemplateEngine
protected void outputCustomFile(@NotNull Map<String, String> customFile, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
String entityName = tableInfo.getEntityName();
String otherPath = this.getPathInfo(OutputFile.other);
customFile.forEach((key, value) -> {
String fileName = String.format(otherPath + File.separator + entityName + File.separator + "%s", key);
this.outputFile(new File(fileName), objectMap, value);
});
}
重写原因:
1)在 Velocity 模板中未找到相关的属性,能获取到数据库表映射实体名称的驼峰命名法,重写此方法获得驼峰实体类命名,便于使用
2、生成多个自定义、定制类时没办法随意指定文件路径,一但存在多个类似名称时,非常不便于查找
3、使用源码方式实在是没有想到如何在自定义、定制生成的类名上加上数据库表映射实体名称
通过以上的种种操作就可以实现自定义、定制的实体信息了
六、Velocity 模板案例
package ${package.Other}.po;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* $!{table.comment} 数据表 ${humpEentityName} 数据库表映射实体驼峰名称
* 基础设施层请求实体
* </p>
*
* @author ${author}
* @since ${date}
*/
@Getter
@Setter
public class ${entity}PO implements Serializable {
private static final long serialVersionUID = 1L;
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!field.comment" != "")
/**
* ${field.comment}
*/
#end
private ${field.propertyType} ${field.propertyName};
#end
/**
* 当前页
*/
private Integer page = 1;
/**
* 每页条数
*/
private Integer pageSize = 20;
}
以上 Velocity 中的相关配置,这里不做相关解释,大家可以直接查看 mybatis plus generator 3.5.1 jar 包中的基础模板中找寻其他配置,你也可以通过 InjectionConfig # beforeOutputFile 方法将入参都打印出来找相应的入参就可以,也可以通过 InjectionConfig # customMap 方法自定义入参。
从上图可看到 mybatis plus generator 3.5.1 在jar 中支持多种生成模板,Velocity只是其中的一种,大家可根据自己的喜好选择相应的模板。
七、总结
mybatis plus generator 的源码相对简单,大家可以通过源码就定制研发。