在项目研发过程中,通过自动化工具生成ORM对象关系映射是一件必不可少的工作。
mybatis plus generator 是一个很好用的工具,在新搭建的项目中研发兄弟尝新,使用了 generator 的3.5.1 和3.5.2 版本,在生成自带的基础工具类的基础上,想再同时生成相应的 PO、VO、DTO和转换工具等实体,发现3.5.1以上关于自定义定制类资料较少,因故写此文章,记录研学结果。希望对大家有用
- <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 | 输出文件之前消费者 | |
customMap(Map | 自定义配置 Map 对象 key:传入参数的名称 value : 传入参数的对象 | 向自定义模板中传入参数和值 |
customFile(Map | 自定义配置模板文件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、使用源码方式实在是没有想到如何在自定义、定制生成的类名上加上数据库表映射实体名称
通过以上的种种操作就可以实现自定义、定制的实体信息了
- package ${package.Other}.po;
-
- import lombok.Getter;
- import lombok.Setter;
- import java.io.Serializable;
- import java.util.Date;
-
- /**
- *
- * $!{table.comment} 数据表 ${humpEentityName} 数据库表映射实体驼峰名称
- * 基础设施层请求实体
- *
- *
- * @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 的源码相对简单,大家可以通过源码就定制研发。