MyBatis Generator 的使用,一看就会的那种

前言

  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的子元素必须按照下面给出的次数和顺序进行配置:

  1. property (0...N)
  2. plugin (0...N)
  3. commentGenerator (0 or 1)
  4. connectionFactoryjdbcConnection,二选一进行配置
  5. javaTypeResolver (0 or 1)
  6. javaModelGenerator(有且仅有 1 次)
  7. sqlMapGenerator (0 or 1)
  8. javaClientGenerator (0 or 1)
  9. 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="`"/> 

注:SqlReservedWords 关键字列表

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

  可以配置01个,用来配置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

  可以配置01个,生成SQL Map的xml文件生成器。在MyBatis3之后,可以使用mapper.xml文件 + Mapper接口,或者只使用Mapper接口 + Annotation;所以,如果javaClientGenerator元素中配置了需要生成xml的话,这个元素就必须配置。该元素有targetPackagetargetProject 两个属性

  • 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,重写我们需要的方法:

  1. 在项目中创建实体类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 + " */");
			}
		}
	}

}

  1. 配置 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
  1. 再次运行主类 MyBatis-Generator,成功的生成了类注释和字段注释~
  2. 还有一点儿需要补充的,上面的示例是继承了 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());
	}
}
  1.  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独泪了无痕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值