• mybatis plus generator 3.5.1 从了解到自定义定制VO、PO、DTO


    一、背景说明:

    在项目研发过程中,通过自动化工具生成ORM对象关系映射是一件必不可少的工作。

    mybatis plus generator 是一个很好用的工具,在新搭建的项目中研发兄弟尝新,使用了 generator 的3.5.1 和3.5.2 版本,在生成自带的基础工具类的基础上,想再同时生成相应的 PO、VO、DTO和转换工具等实体,发现3.5.1以上关于自定义定制类资料较少,因故写此文章,记录研学结果。希望对大家有用

    二、mybatis plus generator jar 包引入

    1. <dependency>
    2. <groupId>com.baomidou</groupId>
    3. <artifactId>mybatis-plus</artifactId>
    4. <version>3.5.1</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>com.baomidou</groupId>
    8. <artifactId>mybatis-plus-generator</artifactId>
    9. <version>3.5.1</version>
    10. </dependency>

    三、开发环境简单介绍

    mac 、jdk 1.8 、idea 、mysql 、使用 Velocity 模板自定义生成工具类(默认)

    四、基础配置使用说明

    1、基础路径信息配置

    1. /**数据库链接地址**/
    2. private static final String JDBC_URL_MAN = "jdbc:mysql://127.0.0.1:3306/myDatabase?useUnicode=true&characterEncoding=UTF-8";
    3. /**数据库登录账号**/
    4. private static final String JDBC_UserName = "root";
    5. /**数据库登录密码**/
    6. private static final String JDBC_Password = "root1234";
    7. /**
    8. * 【需要修改】
    9. * 需要进行生成文件的表名
    10. * 多张表,表名间使用,号分割
    11. **/
    12. private static final String[] Tables = { "user_table"};
    13. /**
    14. * 【需要修改】
    15. * 生成类的注释
    16. * 作者名称
    17. */
    18. private static final String CODE_AUTHOR = "timerbin";
    19. /**
    20. * 生成的文件存放地址 之
    21. * 文件路径
    22. */
    23. private static final String FILE_STORAGE_FILE_ROOT_PATH = System.getProperty("user.dir")+"/user-obj/user-obj-dao/src/test/java/";
    24. /**
    25. * 生成的文件存放地址 之
    26. * 父级 jar包路径
    27. */
    28. private static final String FILE_STORAGE_FILE_JAR_PACKAGE = "com.jd.timer.bin.user.dao";
    29. /**
    30. *
    31. * 生成的文件存放地址 之
    32. * 模块 jar包名称
    33. */
    34. private static final String FILE_STORAGE_FILE_JAR_PACKAGE_MODULE = "build";
    35. /**
    36. * 生成的文件存放地址 之
    37. * Service 接口 存放地址
    38. */
    39. private static final String FILE_STORAGE_SERVICE_FILE_JAR_PACKAGE= "service";
    40. /**
    41. * 生成的文件存放地址 之
    42. * Service impl 实现类 存放地址
    43. */
    44. private static final String FILE_STORAGE_SERVICE_IMPL_FILE_JAR_PACKAGE= "impl";
    45. /**
    46. * 生成的文件存放地址 之
    47. * entity 实体类 存放地址
    48. */
    49. private static final String FILE_STORAGE_ENTITY_FILE_JAR_PACKAGE= "entity";
    50. /**
    51. * 生成的文件存放地址 之
    52. * mapper 操作类 存放地址
    53. */
    54. private static final String FILE_STORAGE_MAPPER_FILE_JAR_PACKAGE= "mapper";
    55. /**
    56. * 生成的文件存放地址 之
    57. * mapper xml 文件 存放地址
    58. */
    59. private static final String FILE_STORAGE_MAPPER_XML_FILE_JAR_PACKAGE= "mapper";
    60. /**
    61. * 自定义 、定制 生成的文件存放地址 之
    62. * other 其他文件 存放地址
    63. */
    64. private static final String FILE_STORAGE_OTHER_FILE_JAR_PACKAGE= "other";

    以上配置主要目的是指定数据库、表,以及生成的基础文件存放路径,此处无需多关注,且朝下看

    2、自动生成工具 main 方法

    1. public static void main(String[] args) {
    2. //设置数据库信息
    3. /***
    4. * 数据库信息配置
    5. */
    6. DataSourceConfig dataSourceConfig = configDataSource();
    7. /**
    8. * 生成工具类
    9. **/
    10. AutoGenerator generator = new AutoGenerator(dataSourceConfig);
    11. /**
    12. * 全局变量配置
    13. */
    14. generator.global(configGlobel());
    15. /**
    16. * 设置生成文件包名地址
    17. */
    18. generator.packageInfo(configPackage());
    19. /**
    20. * 生成文件的策略配置
    21. */
    22. generator.strategy(configStratgy());
    23. /**
    24. * 生成的类的模板配置
    25. */
    26. generator.template(configTemplate());
    27. /**
    28. * 自定义实体信息
    29. **/
    30. generator.injection(initInjectionConfig());
    31. /**
    32. * 自定义模板解析器
    33. */
    34. YaoVelocityTemplateEngine yaoVelocityTemplateEngine = new YaoVelocityTemplateEngine();
    35. generator.execute(yaoVelocityTemplateEngine);
    36. }

    相关jar 包引用

    1. import com.baomidou.mybatisplus.annotation.FieldFill;
    2. import com.baomidou.mybatisplus.annotation.IdType;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. import com.baomidou.mybatisplus.generator.AutoGenerator;
    5. import com.baomidou.mybatisplus.generator.IFill;
    6. import com.baomidou.mybatisplus.generator.config.*;
    7. import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
    8. import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
    9. import com.baomidou.mybatisplus.generator.config.rules.DateType;
    10. import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
    11. import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
    12. import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    13. import com.baomidou.mybatisplus.generator.fill.Column;
    14. import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;

    3、关键各个子方法

    1. /**
    2. * 配置基础转换器
    3. * @return
    4. */
    5. private static DataSourceConfig configDataSource() {
    6. /**数据库链接配置**/
    7. DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(
    8. JDBC_URL_MAN,
    9. JDBC_UserName,
    10. JDBC_Password
    11. )
    12. .dbQuery(new MySqlQuery())
    13. /**自定义转换器,将tinyint 转换为Integer**/
    14. .typeConvert(new EasyMySqlTypeConvert())
    15. .keyWordsHandler(new MySqlKeyWordsHandler())
    16. .build();
    17. return dataSourceConfig;
    18. }
    19. /**
    20. * 自定义转换器转换器 内部类
    21. * 目的将数据库表中定义的 tinyint 或 bit类型转变为 java Integer 类型
    22. * @author timerbin
    23. */
    24. static class EasyMySqlTypeConvert extends MySqlTypeConvert {
    25. @Override
    26. public IColumnType processTypeConvert(GlobalConfig config, String fieldType) {
    27. IColumnType iColumnType = super.processTypeConvert(config, fieldType);
    28. if (fieldType.equals("tinyint(1)")) {
    29. iColumnType = DbColumnType.INTEGER;
    30. }
    31. if (fieldType.equals("bit(1)")) {
    32. iColumnType = DbColumnType.BYTE;
    33. }
    34. return iColumnType;
    35. }
    36. }
    37. /**
    38. * 设置全局变量
    39. * @return
    40. */
    41. private static GlobalConfig configGlobel() {
    42. GlobalConfig globalConfig = new GlobalConfig.Builder()
    43. .fileOverride()
    44. .disableOpenDir()
    45. /**存放生成文件的文件夹地址**/
    46. .outputDir(FILE_STORAGE_FILE_ROOT_PATH)
    47. .author(CODE_AUTHOR)
    48. .dateType(DateType.ONLY_DATE)
    49. .commentDate("yyyy-MM-dd hh:mm:ss")
    50. .build();
    51. return globalConfig;
    52. }
    53. /**
    54. * 生成文件存储目录配置
    55. * @return
    56. */
    57. private static PackageConfig configPackage() {
    58. PackageConfig packageConfig = new PackageConfig.Builder()
    59. /**存放生成文件的 父级 package 地址**/
    60. .parent(FILE_STORAGE_FILE_JAR_PACKAGE)
    61. /**存放生成文件的 的 父级模块地址**/
    62. .moduleName(FILE_STORAGE_FILE_JAR_PACKAGE_MODULE)
    63. /**存放生成文件的 service 接口 存放的package地址**/
    64. .service(FILE_STORAGE_SERVICE_FILE_JAR_PACKAGE)
    65. /**存放生成文件的 service 接口实现类 存放的package地址**/
    66. .serviceImpl(FILE_STORAGE_SERVICE_IMPL_FILE_JAR_PACKAGE)
    67. /**存放生成文件的 实体类 存放的package地址**/
    68. .entity(FILE_STORAGE_ENTITY_FILE_JAR_PACKAGE)
    69. /**存放生成文件的 mapper 操作类 存放的package地址**/
    70. .mapper(FILE_STORAGE_MAPPER_FILE_JAR_PACKAGE)
    71. /**存放生成文件的 mapper 操作类 xml 存放的package地址**/
    72. .xml(FILE_STORAGE_MAPPER_XML_FILE_JAR_PACKAGE)
    73. /**存放生成文件的 其他实体类 存放的package地址**/
    74. .other(FILE_STORAGE_OTHER_FILE_JAR_PACKAGE)
    75. .build();
    76. return packageConfig;
    77. }
    78. /**
    79. * 生成文件的策略配置
    80. * @return
    81. */
    82. private static StrategyConfig configStratgy() {
    83. /**
    84. * 初始化配置
    85. * 策略中实体字段的默认填充装置
    86. *
    87. */
    88. List<IFill> tableFillList = makeInitTableFills();
    89. StrategyConfig strategyConfig = new StrategyConfig.Builder()
    90. .addInclude(Tables)
    91. .entityBuilder()//开始定制实体
    92. /***禁用生成 serialVersionUID**/
    93. // .disableSerialVersionUID()
    94. .enableActiveRecord()
    95. .enableLombok()
    96. .enableRemoveIsPrefix()
    97. .enableTableFieldAnnotation()
    98. .enableChainModel()
    99. .naming(NamingStrategy.underline_to_camel)
    100. .columnNaming(NamingStrategy.underline_to_camel)
    101. /***逻辑删除字段名(数据库)**/
    102. // .logicDeleteColumnName("yn")
    103. .addTableFills(tableFillList)
    104. .idType(IdType.AUTO)
    105. /**格式化实体类文件名称***/
    106. //.formatFileName("%sEntity")
    107. .serviceBuilder()//开始定制Service,由于我们不需要service此处略
    108. /***格式化 service 接口文件名称**/
    109. .formatServiceFileName("%sService")
    110. .formatServiceImplFileName("%sServiceImpl")
    111. .mapperBuilder()//开始定制映射器
    112. .enableMapperAnnotation()
    113. .superClass(BaseMapper.class)
    114. .enableBaseColumnList()
    115. .enableBaseResultMap()
    116. .formatMapperFileName("%sMapper")
    117. .formatXmlFileName("%sMapper")
    118. .build();
    119. return strategyConfig;
    120. }
    121. /**
    122. * 类生成策略
    123. * 配置字段默认填充装置
    124. *
    125. * @return
    126. */
    127. private static List<IFill> makeInitTableFills(){
    128. List<IFill> tableFillList = new ArrayList<>();
    129. /**定义创建时间 插入时默认填充**/
    130. Column createTableFill = new Column("created", FieldFill.INSERT);
    131. /** 定义修改时间 插入或修改时默认填充**/
    132. Column updateTableFill = new Column("modified", FieldFill.INSERT_UPDATE);
    133. tableFillList.add(createTableFill);
    134. tableFillList.add(updateTableFill);
    135. return tableFillList;
    136. }
    137. /**
    138. * 设置其他模板
    139. * @return
    140. */
    141. private static TemplateConfig configTemplate() {
    142. TemplateConfig templateConfig = new TemplateConfig.Builder()
    143. .controller(null)//我不需要controller 此处传null
    144. .service(null)//我不需要service 此处传null
    145. .serviceImpl(null)//我不需要service impl 此处传null
    146. .build();
    147. return templateConfig;
    148. }
    149. /**
    150. *
    151. * @return
    152. */
    153. private static InjectionConfig initInjectionConfig(){
    154. /**自定义生成模板参数**/
    155. Map<String,Object> paramMap = new HashMap<>();
    156. /** 自定义 生成类**/
    157. Map<String,String> customFileMap = new HashMap<>();
    158. /**PO实体**/
    159. customFileMap.put("po"+File.separator+"%sPO.java", "/templates/PO.java.vm");
    160. /**Vo实体**/
    161. customFileMap.put("vo"+File.separator+"%sVO.java", "/templates/VO.java.vm");
    162. /**DTO实体**/
    163. customFileMap.put("dto"+File.separator+"%sDTO.java", "/templates/DTO.java.vm");
    164. return new InjectionConfig.Builder()
    165. .customMap(paramMap)
    166. .customFile(customFileMap)
    167. .build();
    168. }

    以上为配置大多数为mybatis plus generator 3.5.1 的基础配置,网上相关说明资料较多,这里不做过多赘述,以下文章写的较全,大家可以借鉴下。

    详见:mybatis-plus代码生成器及配置 - BlogMemory - 博客园

    五、着重说明-自定义、定制工具类

    1、主要配置方法在以上代码中已列出,为 initInjectionConfig() 方法,需同步配置信息

    1. //1、指定生成的自定文件存放路径
    2. /**存放生成文件的 其他实体类 存放的package地址**/
    3. new PackageConfig.Builder().other(FILE_STORAGE_OTHER_FILE_JAR_PACKAGE);
    4. //2、自定义重新生成自定义、定制类的工具
    5. /**
    6. * 自定义模板解析器
    7. */
    8. TimerVelocityTemplateEngine timerVelocityTemplateEngine = new TimerVelocityTemplateEngine();
    9. //3、定义注入配置方法
    10. /**
    11. * 自定义注入配置
    12. * @return
    13. */
    14. private static InjectionConfig initInjectionConfig(){
    15. /**自定义生成模板参数**/
    16. Map<String,Object> paramMap = new HashMap<>();
    17. /** 自定义 生成类**/
    18. Map<String,String> customFileMap = new HashMap<>();
    19. /**PO实体**/
    20. customFileMap.put("po"+File.separator+"%sPO.java", "/templates/PO.java.vm");
    21. /**Vo实体**/
    22. customFileMap.put("vo"+File.separator+"%sVO.java", "/templates/VO.java.vm");
    23. /**DTO实体**/
    24. customFileMap.put("dto"+File.separator+"%sDTO.java", "/templates/DTO.java.vm");
    25. return new InjectionConfig.Builder()
    26. .customMap(paramMap)
    27. .customFile(customFileMap)
    28. .build();
    29. }
    30. //4、将自定义注入配置放入到 自动工具生成器中
    31. /**
    32. * 自定义实体信息
    33. **/
    34. generator.injection(initInjectionConfig());
    35. //开始执行基础类生成
    36. generator.execute(timerVelocityTemplateEngine);

    2、重点说一下 InjectionConfig 注入配置的属性

    方法说明作用
    beforeOutputFile(BiConsumer>)输出文件之前消费者
    customMap(Map)

    自定义配置 Map 对象

    key:传入参数的名称

    value : 传入参数的对象

    向自定义模板中传入参数和值
    customFile(Map)

    自定义配置模板文件Map

    key:用于定义生成自定义、定制类的名称

    value:用于指定自定义、定制类的模板地址,默认为Velocity模板

    自定义模板名称和模板

    3、详细说明一下 重写的 YaoVelocityTemplateEngine 类

    重写后代码:

    1. import com.baomidou.mybatisplus.generator.config.OutputFile;
    2. import com.baomidou.mybatisplus.generator.config.po.TableInfo;
    3. import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
    4. import com.jd.jsf.gd.util.JsonUtils;
    5. public class TimerVelocityTemplateEngine extends VelocityTemplateEngine {
    6. @Override
    7. protected void outputCustomFile( Map<String, String> customFile, TableInfo tableInfo,Map<String, Object> objectMap) {
    8. //数据库表映射实体名称
    9. String entityName = tableInfo.getEntityName();
    10. String otherPath = this.getPathInfo(OutputFile.other);
    11. //System.out.println(JsonUtils.toJSONString(tableInfo));
    12. //数据库表映射实体名称 驼峰命名法
    13. objectMap.put("humpEentityName",toLowerCaseFirstOne(entityName));
    14. customFile.forEach((key, value) -> {
    15. String fileName = String.format(otherPath + File.separator +key,entityName);
    16. this.outputFile(new File(fileName), objectMap, value);
    17. });
    18. }
    19. /**
    20. * 首字母转为小写
    21. * @param s
    22. * @return
    23. */
    24. private String toLowerCaseFirstOne(String s){
    25. if(Character.isLowerCase(s.charAt(0))) {
    26. return s;
    27. }else {
    28. return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    29. }
    30. }
    31. }

    重写前源码:

    1. //AbstractTemplateEngine
    2. protected void outputCustomFile(@NotNull Map<String, String> customFile, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
    3. String entityName = tableInfo.getEntityName();
    4. String otherPath = this.getPathInfo(OutputFile.other);
    5. customFile.forEach((key, value) -> {
    6. String fileName = String.format(otherPath + File.separator + entityName + File.separator + "%s", key);
    7. this.outputFile(new File(fileName), objectMap, value);
    8. });
    9. }

    重写原因:

    1)在 Velocity 模板中未找到相关的属性,能获取到数据库表映射实体名称的驼峰命名法,重写此方法获得驼峰实体类命名,便于使用

    2、生成多个自定义、定制类时没办法随意指定文件路径,一但存在多个类似名称时,非常不便于查找

    3、使用源码方式实在是没有想到如何在自定义、定制生成的类名上加上数据库表映射实体名称

    通过以上的种种操作就可以实现自定义、定制的实体信息了

    六、Velocity 模板案例 

    1. package ${package.Other}.po;
    2. import lombok.Getter;
    3. import lombok.Setter;
    4. import java.io.Serializable;
    5. import java.util.Date;
    6. /**
    7. *

    8. * $!{table.comment} 数据表 ${humpEentityName} 数据库表映射实体驼峰名称
    9. * 基础设施层请求实体
    10. *

    11. *
    12. * @author ${author}
    13. * @since ${date}
    14. */
    15. @Getter
    16. @Setter
    17. public class ${entity}PO implements Serializable {
    18. private static final long serialVersionUID = 1L;
    19. #foreach($field in ${table.fields})
    20. #if(${field.keyFlag})
    21. #set($keyPropertyName=${field.propertyName})
    22. #end
    23. #if("$!field.comment" != "")
    24. /**
    25. * ${field.comment}
    26. */
    27. #end
    28. private ${field.propertyType} ${field.propertyName};
    29. #end
    30. /**
    31. * 当前页
    32. */
    33. private Integer page = 1;
    34. /**
    35. * 每页条数
    36. */
    37. private Integer pageSize = 20;
    38. }

    以上 Velocity 中的相关配置,这里不做相关解释,大家可以直接查看 mybatis plus generator 3.5.1 jar 包中的基础模板中找寻其他配置,你也可以通过 InjectionConfig # beforeOutputFile 方法将入参都打印出来找相应的入参就可以,也可以通过 InjectionConfig # customMap 方法自定义入参。

    从上图可看到 mybatis plus generator 3.5.1 在jar 中支持多种生成模板,Velocity只是其中的一种,大家可根据自己的喜好选择相应的模板。

    七、总结

    mybatis plus generator 的源码相对简单,大家可以通过源码就定制研发。

  • 相关阅读:
    融合通信 RDS服务器接口定义1.9
    SQL数据库设计 用语言查询数据
    多方面浅谈互联网技术
    操作系统第五章——输入输出管理(上)
    疫情失业之下,测试的未来在哪里
    星巴克推出Web3平台;天啦噜,AI绘画能007了;『决策算法』电子书;合成人脸数据集;面向数据的版本控制;前沿论文 | ShowMeAI资讯日报
    Python反序列化免杀上线CS
    [线性dp]Burenka and Traditions Codeforces1719D1&&D2
    不可思议,无密码登录所有网站!
    【C++干货铺】list的使用 | 模拟实现
  • 原文地址:https://blog.csdn.net/TimerBin/article/details/127799360