mybatis-generator:自定义插件之分页、序列化、集成lombok

0.需求

在我们使用mybatis-generator的过程中,往往其自带的功能不能够满足我们的需求。

此时我们就需要进行插件开发了。

1.准备工作

新建一个Maven项目,引入依赖 mybatis-generator-core

2.开发分页

在mysql中,我们一般使用limit来实现分页

之前的做法是在mybatis-generator生成完成之后手动在Example中两个属性,offset,rows

然后在xml中添加条件判断,追加limit。

这里我们就通过这个思路在开发分页插件。

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

import java.util.List;

public class LimitPlugin extends PluginAdapter {

    @Override
    public boolean validate(List<String> list) {
        return true;
    }

    /**
     * 为每个Example类添加offset和rows属性已经set、get方法
     */
    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

        PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();

        Field rows = new Field();
        rows.setName("rows");
        rows.setVisibility(JavaVisibility.PRIVATE);
        rows.setType(integerWrapper);
        topLevelClass.addField(rows);

        Method setRows = new Method();
        setRows.setVisibility(JavaVisibility.PUBLIC);
        setRows.setName("setRows");
        setRows.addParameter(new Parameter(integerWrapper, "rows"));
        setRows.addBodyLine("this.rows = rows;");
        topLevelClass.addMethod(setRows);

        Method getRows = new Method();
        getRows.setVisibility(JavaVisibility.PUBLIC);
        getRows.setReturnType(integerWrapper);
        getRows.setName("getRows");
        getRows.addBodyLine("return rows;");
        topLevelClass.addMethod(getRows);

        Field offset = new Field();
        offset.setName("offset");
        offset.setVisibility(JavaVisibility.PRIVATE);
        offset.setType(integerWrapper);
        topLevelClass.addField(offset);

        Method setOffset = new Method();
        setOffset.setVisibility(JavaVisibility.PUBLIC);
        setOffset.setName("setOffset");
        setOffset.addParameter(new Parameter(integerWrapper, "offset"));
        setOffset.addBodyLine("this.offset = offset;");
        topLevelClass.addMethod(setOffset);

        Method getOffset = new Method();
        getOffset.setVisibility(JavaVisibility.PUBLIC);
        getOffset.setReturnType(integerWrapper);
        getOffset.setName("getOffset");
        getOffset.addBodyLine("return offset;");
        topLevelClass.addMethod(getOffset);

        return true;
    }

    /**
     * 为Mapper.xml的selectByExample添加limit
     */
    @Override
    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {

        XmlElement ifLimitNotNullElement = new XmlElement("if");
        ifLimitNotNullElement.addAttribute(new Attribute("test", "rows != null"));

        XmlElement ifOffsetNotNullElement = new XmlElement("if");
        ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null"));
        ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${rows}"));
        ifLimitNotNullElement.addElement(ifOffsetNotNullElement);

        XmlElement ifOffsetNullElement = new XmlElement("if");
        ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null"));
        ifOffsetNullElement.addElement(new TextElement("limit ${rows}"));
        ifLimitNotNullElement.addElement(ifOffsetNullElement);

        element.addElement(ifLimitNotNullElement);

        return true;
    }
}

3.集成Lombok、序列化

使用lombok可以使代码更简洁

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;

import java.util.List;

public class LombokPlugin extends PluginAdapter {
    @Override
    public boolean validate(List<String> warnings) {

        return true;
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

        // 添加domain的import
        topLevelClass.addImportedType("lombok.Data");
        topLevelClass.addImportedType("lombok.NoArgsConstructor");
        topLevelClass.addImportedType("lombok.AllArgsConstructor");
        topLevelClass.addImportedType("java.io.Serializable");

        // 添加domain的注解
        topLevelClass.addAnnotation("@Data");
        topLevelClass.addAnnotation("@NoArgsConstructor");
        topLevelClass.addAnnotation("@AllArgsConstructor");

        // 序列化
        generatorDefaultSerialVersionUID(topLevelClass);

        return true;
    }

    // 不生成getter
    @Override
    public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass,
                                              IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {

        return false;
    }

    // 不生成setter
    @Override
    public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass,
                                              IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {

        return false;
    }

    /**
     * 序列化
     *
     * @param topLevelClass
     */
    private void generatorDefaultSerialVersionUID(TopLevelClass topLevelClass) {
        FullyQualifiedJavaType serializable = new FullyQualifiedJavaType("java.io.Serializable");
        topLevelClass.addSuperInterface(serializable);

        Field field = new Field();
        field.setFinal(true);
        field.setInitializationString("1L");
        field.setName("serialVersionUID");
        field.setStatic(true);
        field.setType(new FullyQualifiedJavaType("long"));
        field.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.getFields().add(0, field);
    }
}

4.使用运行

到这里我们就将两个自定义的插件开发完成了。

这里建议是将这两个插件放在一个单独的项目,一是为了方便复用,另一个是我放在同一个项目下的时候,运行好像有点问题。

4.1.打包插件

通过mvn install将我们的插件进行打包,打包为jar包,方便后续使用。

4.2.使用插件

<plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <configuration>
        <configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
        <overwrite>true</overwrite>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>com.xxxx</groupId>
            <artifactId>xxxx</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</plugin>

更改pom.xml,在mybatis-generator的maven插件中引入我们刚刚的项目

<?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>

    <!--导入属性配置 -->
    <properties resource="generator/generator.properties"></properties>

    <!--指定特定数据库的jdbc驱动jar包的位置
        location:
            The full path name of a JAR/ZIP file to add to the classpath,
            or a directory to add to the classpath.
    -->
    <classPathEntry location="${jdbc.driverLocation}"/>

    <context id="default" targetRuntime="Mybatis3">

        <!--使用``包裹mysql关键字-->
        <property name="autoDelimitKeywords" value="true"/>
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <plugin type="com.fdzang.formybatis.config.LombokPlugin"/>
        <plugin type="com.fdzang.formybatis.config.LimitPlugin"/>

        <!-- optional,旨在创建class时,去掉注释 -->
        <commentGenerator>
            <property name="suppressDate" value="false"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <jdbcConnection driverClass="${jdbc.driver}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.username}"
                        password="${jdbc.password}">
        </jdbcConnection>

        <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!--配置实体bean-->
        <javaModelGenerator targetPackage="com.fdzang.microservice.blog.article.dao.domain"
                            targetProject="src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
            <property name="trimStrings" value="false"/>
        </javaModelGenerator>

        <!-- 配置实体bean的mapper.xml-->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 配置实体mapper接口-->
        <javaClientGenerator targetPackage="com.fdzang.microservice.blog.article.dao.mapper"
                             targetProject="src/main/java"
                             type="XMLMAPPER">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <table tableName="test"
               domainObjectName="TestDO"
               mapperName="TestMapper"
               enableInsert="true"
               enableUpdateByPrimaryKey="true"
               enableDeleteByPrimaryKey="true"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="true"
               selectByExampleQueryId="false">
        </table>

    </context>
</generatorConfiguration>

修改generatorConfig.xml,在<context>中引入插件<plugin>,这里有个注意事项是,plugin放置的顺序,需要在<property>下

4.3.运行效果

import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class TestDO implements Serializable {
    private static final long serialVersionUID = 1L;

    private Integer id;

    private String test;
}

Example,去掉了其他部分。

public class TestDOExample {
    private Integer rows;

    private Integer offset;

    public TestDOExample() {
        oredCriteria = new ArrayList<Criteria>();
    }
    
    public void setRows(Integer rows) {
        this.rows = rows;
    }

    public Integer getRows() {
        return rows;
    }

    public void setOffset(Integer offset) {
        this.offset = offset;
    }

    public Integer getOffset() {
        return offset;
    }
}

Mapper

<select id="selectByExample" parameterType="com.fdzang.microservice.blog.article.dao.domain.TestDOExample" resultMap="BaseResultMap">
  select
  <if test="distinct">
    distinct
  </if>
  'false' as QUERYID,
  <include refid="Base_Column_List" />
  from test
  <if test="_parameter != null">
    <include refid="Example_Where_Clause" />
  </if>
  <if test="orderByClause != null">
    order by ${orderByClause}
  </if>
  <if test="rows != null">
    <if test="offset != null">
      limit ${offset}, ${rows}
    </if>
    <if test="offset == null">
      limit ${rows}
    </if>
  </if>
</select>

5.其他

其实自定义mybatis-generator的插件,主要是通过继承PluginAdapter来实现的。

PluginAdapter中还有很多其他的方法,可以进行自定义修改,大家可以根据需要进行自定义改造。

 

参考:

http://xxgblog.com/2016/05/06/mybatis-generator-mysql-pagination/

https://www.jianshu.com/p/b243f3ec8419

posted @ 2020-05-07 16:09  市井俗人  阅读(1687)  评论(0编辑  收藏  举报