前言
MyBatis-Generator是MyBatis提供的一个代码生成工具,可以帮助我们生成数据库表对应的持久化对象(也称作 Model、PO)、操作数据库的接口(dao)、简单 SQL 的 mapper(XML 形式或注解形式)。
MyBatis-GeneratorMyBatis-Generator 是一个独立工具,你可以下载它的 jar 包来运行,也可以在Ant和Maven中运行。其官方网址为:mybatis.org/generator/
引入 MyBatis-Generator
既然需要使用 MyBatis-Generator,那么在项目中就一定使用了 MyBatis 和某一种数据库,并且这些依赖应该已经在 Maven 中配置好了。例如 pom 文件中的配置:
<dependencies>
<!-- 为了方便,不展示其它配置... -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- mybatis 代码自动生成器 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
</dependencies>
MyBatis-Generator 配置文件
MyBatis-Generator需要一个xml配置文件,来详细配置生成代码的各种细节。例如,在项目的resources目录下新建一个mybatis-generator-config.xml配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
connectionURL="jdbc:db2:TEST"
userId="db2admin"
password="db2admin">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<javaModelGenerator targetPackage="test.model" targetProject="\MBGTestProject\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="test.xml" targetProject="\MBGTestProject\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="test.dao" targetProject="\MBGTestProject\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
<property name="useActualColumnNames" value="true"/>
<generatedKey column="ID" sqlStatement="DB2" identity="true" />
<columnOverride column="DATE_FIELD" property="startDate" />
<ignoreColumn column="FRED" />
<columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
</table>
</context>
</generatorConfiguration>
引入外部配置文件
properties 元素
properties可以用于加载配置项或者配置文件,在整个配置文件中就可以使用 ${propertyKey} 的方式来引用配置项,该元素有两个属性,均用来指定外部配置文件的地址:
- resource:配置资源加载地址,使用resource,从classpath开始找
- url:配置资源加载地质,使用URL的方式
注意,这两个属性只能选择一个使用。
用于引入文件的代码如下:
<properties resource="mybatis-generator.properties"/>
classPathEntry 元素
使用 classPathEntry 元素,可以在加载需要的额外的依赖包,其中,location 属性指明需要加载的 jar/zip 包的全路径。
<!-- 指定数据库驱动的jdbc驱动jar包的位置 -->
<classPathEntry location="./mysql-connector-java-5.1.40.jar"/>
配置 generationConfiguration
context 元素
在 generationConfiguration 的子元素中,context 是核心元素,用于配置生成一组对象的环境。元素 context 有 4 个属性可供配置:
- id:必填,上下文 id,用于在生成错误时提示;保证多个 context 的 id 不重复就行。
- defaultModelType:用于指定生成对象的样式
- conditional:类似hierarchical;
- flat:所有内容(主键,blob)等全部生成在一个对象中;
- hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class)
- targetRuntime:用于指定生成的代码的运行时环境,这个配置会影响生成的 dao 和 mapper.xml 的内容
- MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample;
- MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample;
- 还有其它可配置的值,详情见 官网 。
- introspectedColumnImpl:类全限定名,用于扩展MBG
<context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
...
</context>
context 的子元素
元素 context 中,有多个子元素需要配置。同样的,context的子元素必须按照下面给出的次数和顺序进行配置:
- property (0...N)
- plugin (0...N)
- commentGenerator (0 or 1)
- connectionFactory 和 jdbcConnection,二选一进行配置
- javaTypeResolver (0 or 1)
- javaModelGenerator(有且仅有 1 次)
- sqlMapGenerator (0 or 1)
- javaClientGenerator (0 or 1)
- table (1...N)
property
用于为代码生成指定属性,或为其它元素指定属性。可以配置零个或多个,常见的property配置如下:
<!--
自动识别数据库关键字,默认为false。一般保留默认值,遇到数据库关键字时,按照table元素中columnOverride属性的配置进行覆盖;
如果设置为 true, 则需按照 SqlReservedWords 中定义的关键字列表,对关键字进行定界(分隔);
定界符(分隔符)参见 beginningDelimiter 和 endingDelimiter 的设置-->
<property name="autoDelimitKeywords" value="true"/>
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 格式化java代码 -->
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
<!-- 格式化XML代码 -->
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
<!-- 指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
plugin
配置插件,可以有零个或多个,常见的 plugin 配置有:
<!-- 使生成的 Model 实现 Serializable 接口 -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<!-- 为生成的 Model 覆写 toString() 方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<!-- 为生成的 Model 覆写 equals() 和 hashCode() 方法 -->
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>
<!-- 生成mysql带有分页的sql的插件 这个可以自己写,-->
<plugin type="generator.MysqlPaginationPlugin" />
commentGenerator
可以配置0个或1个,用来配置生成的注释,默认是生成注释的,并且会在注释中添加时间等信息。但生成的注释信息没有任何价值,因而一般情况下都会屏蔽注释信息。其中type属性,以用来指定自己的注释实现类,继承DefaultCommentGenerator重写一些方法。
<commentGenerator>
<!-- 生成的注释中是否不包含时间信息,默认为false -->
<property name="suppressDate" value="false" />
<!-- 生成的注释中,时间的显示格式 -->
<property name="dateFormat" value="yyyy-MM-dd"/>
<!-- 是否去除自动生成的注释 -->
<property name="suppressAllComments" value="false" />
<!-- 是否添加数据库内的注释 -->
<property name="addRemarkComments" value="true"/>
</commentGenerator>
jdbcConnection
配置数据库连接,具体如下:
<!--
driverClass:访问数据库的JDBC驱动程序的完全限定类名
connectionURL:访问数据库的JDBC连接URL
userId:访问数据库的用户ID
password:访问数据库的密码
-->
<jdbcConnection
driverClass="${spring.datasource.driverClassName}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
<!-- 针对oracle数据库 -->
<property name="remarksReporting" value="true"></property>
<!-- 针对mysql数据库 -->
<property name="useInformationSchema" value="true"></property>
</jdbcConnection>
其中,${propertyKey}里面是引用的外部配置文件中的propertyValue,当然也可以写死,那么就不用在,<properties resource=""/> 中引入此文件了。
javaTypeResolver
可以配置0或1个,用来配置JDBC到Java中的类型转换规则,如果不进行配置,则使用默认的转换规则,默认使用: <font color="red">org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl。
javaModelGenerator
Java模型生成器,有且仅能配置一个,负责key类(context元素的defaultModelType属性)、JavaBean实体类、查询类的生成。javaModelGenerator 有两个属性:
- targetPackage
- 生成实体类存放的包名,一般就是放在该包下
- targetProject
- 指定目标项目路径(一个已存在的目录),可以是绝对路径或相对路径(如targetProject="src/main/java"),生成的内容会放到指定目录中
<!--生成entity类存放位置-->
<javaModelGenerator targetPackage="org.dllwh.model" targetProject="src/main/java">
</javaModelGenerator>
在 javaModelGenerator 元素中还可以配置多个 property 子元素,具体代码如下:
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
sqlMapGenerator
可以配置0或1个,生成SQL Map的xml文件生成器。在MyBatis3之后,可以使用mapper.xml文件 + Mapper接口,或者只使用Mapper接口 + Annotation;所以,如果javaClientGenerator元素中配置了需要生成xml的话,这个元素就必须配置。该元素有targetPackage 和 targetProject 两个属性
- targetPackage
- 生成实体类存放的包名,一般就是放在该包下
- targetProject
- 指定目标项目路径,可以是绝对路径或相对路径(如targetProject="src/main/resources")
<sqlMapGenerator targetPackage="org.dllwh.dao.impl" targetProject="src/main/java">
</sqlMapGenerator>
javaClientGenerator
用于配置关于Mapper接口的生成,配置0或1个。注意,如果没有配置该元素,那么默认不会生成Mapper接口。其有 3 个属性:
- type:该属性用于选择一个预定义的客户端代码(可以理解为Mapper接口)生成器,用户可以自定义实现
- ANNOTATEDMAPPER:会生成使用Mapper接口+Annotation的方式创建(SQL生成在annotation中),不会生成对应的XML;
- MIXEDMAPPER:使用混合配置,会生成Mapper接口,并适当添加合适的Annotation,但是XML会生成在XML中;
- XMLMAPPER:会生成Mapper接口,接口完全依赖XML;
- targetPackage:生成实体类存放的包名,一般就是放在该包下
- targetProject:指定目标项目路径,可以是绝对路径或相对路径(如 targetProject="src/main/java")
一般建议将 type 设置成 XMLMAPPER
<javaClientGenerator type="XMLMAPPER" targetPackage="org.dllwh.dao" targetProject="src/main/java">
<!-- 可以为所有生成的接口添加一个父接口,但是只负责生成,不负责检查 -->
<!-- <property name="rootInterface" value=""/> -->
</javaClientGenerator>
table
指定数据库表,要生成哪些表,就写哪些表,要和数据库中对应,不能写错!
一个 table 元素对应一张数据库表,如果想同时为多张表生成代码,需要配置多个 table 元素;或者可以将 tableName 设置为 % 来为全部表生成代码。
属性 | 是否必须 | 说明 |
---|---|---|
tableName | ✓ | 指定要生成的表名,可以使用SQL通配符匹配多个表。注意:大小写敏感问题 |
schema | × | 为数据库名,oracle需要配置,mysql不需要配置 |
catalog | × | 数据库的 catalog |
domainObjectName | × | 生成实体对象的类名。如果没有指定,会自动根据表名来生成名称 |
enableInsert | × | 指定是否生成insert语句,默认true |
enableSelectByPrimaryKey | × | 指定是否生成按照主键查询对象的语句(就是getById或get),默认true |
enableSelectByExample | × | 指定是否生成动态查询语句,默认true |
enableUpdateByPrimaryKey | × | 指定是否生成按照主键update对象的语句,默认true |
enableDeleteByPrimaryKey | × | 指定是否生成按照主键delete对象的语句,默认true |
enableDeleteByExample | × | 指定是否生成动态delete语句,默认true |
enableCountByExample | × | 指定是否生成动态查询总条数语句(用于分页的总条数查询),默认true |
enableUpdateByExample | × | 指定是否生成动态修改语句(只修改对象中不为空的属性),默认true |
delimitAllColumns | × | 设置是否所有生成的SQL中的列名都使用标识符引起来 |
此外,table 元素中还可以配置多个 property 和 columnOverride 等子元素。示例代码如下:
<!--
指定是否只生成domain类,如果设置为true,只生成domain类。
如果还配置了sqlMapGenerator,那么在 mapper.xml 文件中,只生成 resultMap 元素
-->
<property name="modelOnly" value="false"/>
<!-- 可以为生成的类会继承这个类 -->
<!-- <property name="rootClass" value=""/> -->
<!-- 可以为生成的类添加一个父接口 -->
<!-- <property name="rootInterface" value=""/> -->
<!-- 如果设置为true,生成的model类会直接使用column本身的名字,而不会再使用驼峰命名方法 -->
<property name="useActualColumnNames" value="false"/>
<!-- 生成主键的方法,如果设置了该元素,会在生成的<insert>元素中生成一条正确的<selectKey>元素 -->
<!-- <generatedKey column="id" sqlStatement="MySql" identity="true"/>-->
<generatedKey column="id" sqlStatement="SELECT LAST_INSERT_ID()"/>
<!-- 用来修改表中某个列的属性,MBG 会根据修改后的配置来生成 domain 的属性;
column:要重新设置的列名;一个 table 元素中可以定义多个 columnOverride 元素哈 -->
<columnOverride column="show_status">
<!-- 使用 property 属性来指定列要生成的属性名称 -->
<property name="property" value="showStatus"/>
<!-- javaType 用于指定生成的 domain 的属性类型,使用类型的全限定名-->
<property name="javaType" value="java.lang.Integer"/>
<!-- jdbcType用于指定该列的JDBC类型
<property name="jdbcType" value=""/>
-->
</columnOverride>
MyBatis-Generator 配置示例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 所有的配置均在根元素 generatorConfiguration 下 -->
<generatorConfiguration>
<properties resource="mybatis-generator.properties" />
<context id="MySqlContext" targetRuntime="MyBatis3">
<property name="autoDelimitKeywords" value="true" />
<property name="javaFileEncoding" value="UTF-8" />
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter" />
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter" />
<property name="beginningDelimiter" value="`" />
<property name="endingDelimiter" value="`" />
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<commentGenerator>
<property name="suppressDate" value="true" />
<property name="dateFormat" value="yyyy-MM-dd" />
<property name="suppressAllComments" value="true" />
<property name="addRemarkComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="${spring.datasource.driverClassName}"
connectionURL="${spring.datasource.url}" userId="${spring.datasource.username}"
password="${spring.datasource.password}" />
<javaModelGenerator targetPackage="org.dllwh.model" targetProject="src/main/java">
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="org.dllwh.dao.impl" targetProject="src/main/java">
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="org.dllwh.dao" targetProject="src/main/java">
</javaClientGenerator>
<table tableName="sys_menu" enableInsert="true" enableSelectByPrimaryKey="true" enableSelectByExample="false"
enableUpdateByPrimaryKey="true" enableDeleteByPrimaryKey="true" enableDeleteByExample="false"
enableCountByExample="false" enableUpdateByExample="false">
<property name="modelOnly" value="false" />
<property name="useActualColumnNames" value="false" />
<!-- -->
</table>
</context>
</generatorConfiguration>
运行 MyBatis-Generator
使用 Java 代码编程运行,需要按照方式一在Maven的pom文件中引入依赖。然后在项目中新建一个 Java 类,代码类似下面:
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class GeneratorSqlmap {
public void defaultCommentGenerator() throws Exception {
// MyBatis-Generator 执行过程中的警告信息
List<String> warnings = new ArrayList<String>();
// 当生成的代码重复时,覆盖原代码
boolean overwrite = true;
// 指向逆向工程配置文件
String genCfg = "/generatorConfig.xml";
// 读取 MyBatis-Generator 配置文件
File configFile = new File(GeneratorSqlmap.class.getResource(genCfg).getFile());
// 初始化配置解析器
ConfigurationParser cp = new ConfigurationParser(warnings);
// 调用配置解析器创建配置对象
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
// 创建一个MyBatisGenerator对象。MyBatisGenerator类是真正用来执行生成动作的类
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
// 执行生成代码
myBatisGenerator.generate(null);
// 输出警告信息
warnings.forEach(warning -> System.out.println(warning));
}
public static void main(String[] args) throws Exception {
try {
GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
generatorSqlmap.defaultCommentGenerator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyBatis Generator 自定义扩展
自定义生成注释
commentGenerator生成的是由org.mybatis.generator.api.CommentGenerator来控制的,这是一个接口,MyBatis Generator的默认实现类是 org.mybatis.generator.internal.DefaultCommentGenerator。当你在generatorConfig.xml中配置了 commentGenerator 标签,那么默认状态下,生成注释的工作,将由 DefaultCommentGenerator 来完成。
运行 MyBatis-Generator后,查看生成的代码,怎么说呢,数据库注释倒是拿到了,但是生成的一堆其他信息,看着实在是太扎眼了。查看源码,发现这些内容已经写死在<font color="#e83e8c">DefaultCommentGenerator中了,没有办法自定义。
自己动手丰衣足食,我们为啥不自己写个类实现<font color="#900">CommentGenerator接口,然后自定义自己想要的注释呢。观察<font color="#900">CommentGenerator接口,发现里面的方法非常多,不仅包含了生成 Java 实体注释对应的方法,还包括了生成XML中注释的方法。所以我们先定义我们自己的注释类<font color="blue">CustomSQLCommentGenerator,继承<font color="red">DefaultCommentGenerator,重写我们需要的方法:
- 在项目中创建实体类CustomSQLCommentGenerator
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.DefaultCommentGenerator;
public class CustomSQLCommentGenerator extends DefaultCommentGenerator {
/** 属性,即配置在 commentGenerator 标签之内的 Property 标签 */
private Properties properties;
/** 生成的注释中是否不包含时间信息,默认为false */
private boolean suppressDate;
/** 是否去除自动生成的注释 */
private boolean suppressAllComments;
/** 是否添加数据库内的注释 */
private boolean addRemarkComments;
/** properties配置文件 */
private Properties systemPro;
/** 生成的注释中,时间的显示格式 */
private SimpleDateFormat dateFormat;
/** 自定义属性 - 创建人 */
private String author;
/** 自定义属性 - 创建邮箱 */
private String email;
/** 自定义属性 - 版本 */
private String version;
/** 自定义属性 - 是否添加get注释 */
private boolean addGetComments;
/** 自定义属性 - 是否添加set注释 */
private boolean addSetComments;
public CustomSQLCommentGenerator() {
super();
properties = new Properties();
systemPro = System.getProperties();
suppressDate = false;
suppressAllComments = false;
addRemarkComments = true;
}
/**
* 从该配置中的任何属性添加此实例的属性CommentGenerator配置,这个方法将在任何其他方法之前被调用。
*/
@Override
public void addConfigurationProperties(Properties properties) {
// 获取自定义的 properties
this.properties.putAll(properties);
author = properties.getProperty("author", "");
email = properties.getProperty("email", "");
version = properties.getProperty("version", "V 1.0.1");
addGetComments = "false".equalsIgnoreCase(properties.getProperty("addGetComments")) ? false : true;
addSetComments = "false".equalsIgnoreCase(properties.getProperty("addSetComments")) ? false : true;
String dateFormatString = properties.getProperty("dateFormat", "yyyy-MM-dd HH:mm:ss");
if (StringUtility.stringHasValue(dateFormatString)) {
dateFormat = new SimpleDateFormat(dateFormatString);
}
}
/**
* 创建的数据表对应的类添加的注释
*/
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (suppressAllComments || !addRemarkComments) {
return;
}
topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * 把今天最好的表现当作明天最新的起点..~");
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * Today the best performance as tomorrow newest starter!");
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @类描述 : TODO(这里用一句话描述这个类的作用)");
// 数据库表名
String tableName = introspectedTable.getFullyQualifiedTableNameAtRuntime();
// 获取表注释
String tableRemarks = introspectedTable.getRemarks();
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @数据表 : " + tableName);
if (StringUtils.isNotBlank(tableRemarks)) {
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @数据表注释 : " + tableRemarks);
}
topLevelClass.addJavaDocLine(" * ");
if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(author)) {
topLevelClass.addJavaDocLine(" * @author : <a href=\"mailto:" + email + "\"> " + author + "</a>");
} else if (StringUtils.isNotBlank(author) && StringUtils.isBlank(email)) {
topLevelClass.addJavaDocLine(" * @author : " + author);
}
topLevelClass.addJavaDocLine(" * @创建时间 : " + getDateString());
topLevelClass.addJavaDocLine(" * @版本 : " + version);
topLevelClass.addJavaDocLine(" * @since : " + systemPro.getProperty("java.version"));
topLevelClass.addJavaDocLine(" * @see <a href=\"\">TODO(连接内容简介)</a>");
topLevelClass.addJavaDocLine(" */");
}
/**
* 生成xx.java文件(model)属性的注释,注释为空就不给属性添加。
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
// 获取列注释
String remarks = introspectedColumn.getRemarks();
// 开启注释,并且数据库中comment有值
if (addRemarkComments && StringUtils.isNotBlank(remarks)) {
// 通过换行符分割
String[] remarkLines = remarks.split(systemPro.getProperty("line.separator"));
int length = remarkLines.length;
// 如果有多行,就换行显示
if (length > 1) {
// 注释开始的地方
field.addJavaDocLine("/**");
for (int i = 0; i < length; i++) {
field.addJavaDocLine(" * " + remarkLines[i]);
}
// 注释结束
field.addJavaDocLine(" */");
} else {
field.addJavaDocLine("/** " + remarks + " */");
}
}
}
}
- 配置 generatorConfig.xml设置我们自己的注释生成器:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 所有的配置均在根元素 generatorConfiguration 下 -->
<generatorConfiguration>
<properties resource="mybatis-generator.properties" />
<context id="MySqlContext" targetRuntime="MyBatis3">
<property name="autoDelimitKeywords" value="true" />
<property name="javaFileEncoding" value="UTF-8" />
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter" />
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter" />
<property name="beginningDelimiter" value="`" />
<property name="endingDelimiter" value="`" />
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<!-- 自定义comment生成器地址 -->
<commentGenerator type="org.dllwh.template.database.mybatis.custom.CustomSQLCommentGenerator">
<property name="author" value="${custom.property.author}" />
<property name="email" value="${custom.property.email}" />
<property name="version" value="V 1.0.1" />
<property name="addGetComments" value="false" />
<property name="addSetComments" value="false" />
</commentGenerator>
<jdbcConnection driverClass="${spring.datasource.driverClassName}"
connectionURL="${spring.datasource.url}" userId="${spring.datasource.username}"
password="${spring.datasource.password}" />
<javaModelGenerator targetPackage="${model.target.package}" targetProject="${target.project}">
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="${mapper.target.package}" targetProject="${target.project}">
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="${dao.target.package}" targetProject="${target.project}">
</javaClientGenerator>
<table tableName="sys_menu" enableInsert="true" enableSelectByPrimaryKey="true" enableSelectByExample="false"
enableUpdateByPrimaryKey="true" enableDeleteByPrimaryKey="true" enableDeleteByExample="false"
enableCountByExample="false" enableUpdateByExample="false">
<property name="modelOnly" value="false" />
<property name="useActualColumnNames" value="false" />
<!-- -->
</table>
</context>
</generatorConfiguration>
其中:mybatis-generator.properties属性文件内容如下:
#Mybatis Generator configuration
# 自定义comment生成器地址
customCommentGenerator.address=org.dllwh.template.database.mybatis.custom.CustomSQLCommentGenerator
# 自定义属性 - 创建人
customCommentGenerator.property.author=独泪了无痕
# 自定义属性 - 创建邮箱
customCommentGenerator.property.email=duleilewuhen@sina.com
# 自定义属性 - 版本
customCommentGenerator.property.version=V 1.0.1
# 自定义属性 - 是否添加get注释
customCommentGenerator.property.addGetComments=false
# 自定义属性 - 是否添加set注释
customCommentGenerator.property.addSetComments=false
# java的目录路径
target.project=src/main/java
# resources的目录路径
target.resources=src/main/resources
# 类根地址
target.prefix=org.dllwh
# 生成实体类地址
model.target.package=org.dllwh.model
# 生成dao接口(mapper)地址
dao.target.package=org.dllwh.dao
# 生成mapper(xml)地址
mapper.target.package=org.dllwh.dao.impl
# 数据库信息
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.username=spring
spring.datasource.password=spring
- 再次运行主类 MyBatis-Generator,成功的生成了类注释和字段注释~
- 还有一点儿需要补充的,上面的示例是继承了 DefaultCommentGenerator 实现的,也可以通过实现CommentGenerator 接口实现。
import static org.mybatis.generator.internal.util.StringUtility.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.InnerEnum;
import org.mybatis.generator.api.dom.java.JavaElement;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.MergeConstants;
import org.mybatis.generator.internal.util.StringUtility;
/**
* 把今天最好的表现当作明天最新的起点..~
*
* Today the best performance as tomorrow newest starter!
*
* @类描述: MyBatis Generator 自定义comment生成器.
* @author: <a href="mailto:duleilewuhen@sina.com">独泪了无痕</a>
* @创建时间: 2020-04-10
* @版本: V 1.0.1
* @since: JDK 1.8
*/
public class CustomSQLCommentGenerator implements CommentGenerator {
/** 属性,即配置在 commentGenerator 标签之内的 Property 标签 */
private Properties properties;
/** 生成的注释中是否不包含时间信息,默认为false */
private boolean suppressDate;
/** 是否去除自动生成的注释 */
private boolean suppressAllComments;
/** 是否添加数据库内的注释 */
private boolean addRemarkComments;
/** properties配置文件 */
private Properties systemPro;
/** 生成的注释中,时间的显示格式 */
private SimpleDateFormat dateFormat;
/** 自定义属性 - 创建人 */
private String author;
/** 自定义属性 - 创建邮箱 */
private String email;
/** 自定义属性 - 版本 */
private String version;
/** 自定义属性 - 是否添加get注释 */
private boolean addGetComments;
/** 自定义属性 - 是否添加set注释 */
private boolean addSetComments;
public CustomSQLCommentGenerator() {
super();
properties = new Properties();
systemPro = System.getProperties();
suppressDate = false;
suppressAllComments = false;
addRemarkComments = true;
}
/**
* 从该配置中的任何属性添加此实例的属性CommentGenerator配置,这个方法将在任何其他方法之前被调用。
*/
@Override
public void addConfigurationProperties(Properties properties) {
// 获取自定义的 properties
this.properties.putAll(properties);
author = properties.getProperty("author", "");
email = properties.getProperty("email", "");
version = properties.getProperty("version", "V 1.0.1");
addGetComments = isTrue(properties.getProperty("addGetComments")) ? true : false;
addSetComments = isTrue(properties.getProperty("addSetComments")) ? true : false;
String dateFormatString = properties.getProperty("dateFormat", "yyyy-MM-dd HH:mm:ss");
if (stringHasValue(dateFormatString)) {
dateFormat = new SimpleDateFormat(dateFormatString);
}
}
/**
* 生成xx.java文件(model)属性的注释,注释为空就不给属性添加。
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
// 获取列注释
String remarks = introspectedColumn.getRemarks();
// 开启注释,并且数据库中comment有值
if (addRemarkComments &&stringHasValue(remarks)) {
// 通过换行符分割
String[] remarkLines = remarks.split(systemPro.getProperty("line.separator"));
int length = remarkLines.length;
// 如果有多行,就换行显示
if (length > 1) {
// 注释开始的地方
field.addJavaDocLine("/**");
for (int i = 0; i < length; i++) {
field.addJavaDocLine(" * " + remarkLines[i]);
}
// 注释结束
field.addJavaDocLine(" */");
} else {
field.addJavaDocLine("/** " + remarks + " */");
}
}
}
/**
* Java属性注释,注释为空就不给属性添加。
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
}
/**
* 创建的数据表对应的类添加的注释
*/
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (suppressAllComments || !addRemarkComments) {
return;
}
topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * 把今天最好的表现当作明天最新的起点..~");
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * Today the best performance as tomorrow newest starter!");
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @类描述 : TODO(这里用一句话描述这个类的作用)");
// 数据库表名
String tableName = introspectedTable.getFullyQualifiedTableNameAtRuntime();
// 获取表注释
String tableRemarks = introspectedTable.getRemarks();
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @数据表 : " + tableName);
if (stringHasValue(tableRemarks)) {
topLevelClass.addJavaDocLine(" * ");
topLevelClass.addJavaDocLine(" * @数据表注释 : " + tableRemarks);
}
topLevelClass.addJavaDocLine(" * ");
if (stringHasValue(email) && stringHasValue(author)) {
topLevelClass.addJavaDocLine(" * @author : <a href=\"mailto:" + email + "\"> " + author + "</a>");
} else if (stringHasValue(author) && !stringHasValue(email)) {
topLevelClass.addJavaDocLine(" * @author : " + author);
} else if (stringHasValue(email) && !stringHasValue(author)) {
topLevelClass.addJavaDocLine(" * @email : " + email);
}
topLevelClass.addJavaDocLine(" * @创建时间 : " + getDateString());
topLevelClass.addJavaDocLine(" * @版本 : " + version);
topLevelClass.addJavaDocLine(" * @since : " + systemPro.getProperty("java.version"));
topLevelClass.addJavaDocLine(" * @see <a href=\"\">TODO(连接内容简介)</a>");
topLevelClass.addJavaDocLine(" */");
}
/**
* Java类的类注释
*/
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
}
/**
* Java类的类注释
*/
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
if (suppressAllComments) {
return;
}
}
/**
* 为枚举添加注释
*/
@Override
public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
}
/**
* 数据库对应实体类的Getter方法注解
*/
@Override
public void addGetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments || !addGetComments) {
return;
}
method.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
sb.append(" * ");
if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString());
method.addJavaDocLine(" *");
}
sb.setLength(0);
sb.append(" * @return ");
sb.append(introspectedColumn.getActualColumnName());
if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {
sb.append(" - ");
sb.append(introspectedColumn.getRemarks());
}
method.addJavaDocLine(sb.toString());
method.addJavaDocLine(" */");
return;
}
/**
* 数据库对应实体类的Setter方法注解
*/
@Override
public void addSetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (suppressAllComments || !addSetComments) {
return;
}
method.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {
sb.append(" * ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString());
method.addJavaDocLine(" *");
}
Parameter parm = method.getParameters().get(0);
sb.setLength(0);
sb.append(" * @param ");
sb.append(parm.getName());
if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {
sb.append(" ");
sb.append(introspectedColumn.getRemarks());
}
method.addJavaDocLine(sb.toString());
method.addJavaDocLine(" */");
}
/**
* 普通方法的注释,这里主要是XXXMapper.java里面的接口方法的注释
*/
@Override
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
method.addJavaDocLine("/**");
method.addJavaDocLine(" * @方法描述 : " + method.getName());
method.addJavaDocLine(" * ");
List<Parameter> parameters = method.getParameters();
parameters.forEach(parameter -> method.addJavaDocLine(" * @param " + parameter.getName()));
method.addJavaDocLine(" * ");
// 如果有返回类型,添加@return
String returnType = "void";
if (!returnType.equals(method.getReturnType().toString())) {
method.addJavaDocLine(" * @return ");
}
// addJavadocTag(method, false);
method.addJavaDocLine(" */");
}
/**
* 给Java文件加注释,这个注释是在文件的顶部,也就是package上面。
*/
@Override
public void addJavaFileComment(CompilationUnit compilationUnit) {
compilationUnit.addFileCommentLine("/*");
compilationUnit.addFileCommentLine("*");
compilationUnit.addFileCommentLine("* " + compilationUnit.getType().getShortName() + ".java");
compilationUnit.addFileCommentLine("* Copyright(C) 2017-2020 xxx公司");
compilationUnit.addFileCommentLine("* ALL rights reserved.");
compilationUnit.addFileCommentLine("* @date " + getDateString() + "");
compilationUnit.addFileCommentLine("*/");
}
/**
* Mybatis的Mapper.xml文件里面的注释
*/
@Override
public void addComment(XmlElement xmlElement) {
if (suppressAllComments) {
return;
}
}
/**
* 为调用此方法作为根元素的第一个子节点添加注释。
*/
@Override
public void addRootComment(XmlElement rootElement) {
}
/**
* @方法描述 : 返回格式化的日期字符串以包含在Javadoc标记中和XML注释。 如果您不想要日期,则可以返回null在这些文档元素中。
* @return 格式化后的日期
*/
protected String getDateString() {
if (suppressDate) {
return null;
} else if (dateFormat != null) {
return dateFormat.format(new Date());
} else {
return new Date().toString();
}
}
/**
* @方法描述: 此方法为其添加了自定义javadoc标签。
*
* @param javaElement
* @param markAsDoNotDelete
*/
protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {
javaElement.addJavaDocLine(" *");
StringBuilder sb = new StringBuilder();
sb.append(" * ");
sb.append(MergeConstants.NEW_ELEMENT_TAG);
if (markAsDoNotDelete) {
sb.append(" do_not_delete_during_merge");
}
String s = getDateString();
if (s != null) {
sb.append(' ');
sb.append(s);
}
javaElement.addJavaDocLine(sb.toString());
}
}