Writing spring boot MyBatis paging plug-in from scratch

Source: Internet
Author: User
Tags prepare throwable

first, the final effect :











Paging can be implemented without any action after passing in page and page size sizes only after a specific paging object (pageable) is passed in mapper

Effects, similar to the paging capabilities of spring data JPA and Mybatis-plus.



I. File structure and configuration
Build.gradle:

Buildscript {
	ext {
		springbootversion = ' 1.5.9.RELEASE '
	}
	repositories {
		mavencentral ()
	}
	Dependencies {
		classpath ("Org.springframework.boot:spring-boot-gradle-plugin:${springbootversion}")
	}
}

Apply plugin: ' java '
apply plugin: ' idea '
apply plugin: ' org.springframework.boot '

group = ' Org.zhu '
Version = ' 0.0.1-snapshot '
sourcecompatibility = 1.8

Repositories {
	mavencentral ()
}


Dependencies {
	compile (' org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1 ')
	compile (' Org.springframework.boot:spring-boot-starter-web ')
	runtime (' Mysql:mysql-connector-java ')
	testcompile (' Org.springframework.boot:spring-boot-starter-test ')
}

File structure:


MyBatis Configuration:
Application.properties:
# =============================== #
= DATA SOURCE
# ===============================

Spring.datasource.url = jdbc:mysql://localhost:3306/test?createdatabaseifnotexist=true&characterencoding\= Utf-8
spring.datasource.userName = root
Spring.datasource.password = 
Spring.datasource.testWhileIdle = True
spring.datasource.validationQuery = SELECT 1

# ===============================
# = MyBatis
# = = = = ============================
mybatis.mapper-locations = Classpath*:mapper/*.xml
Mybatis.check-config-location=true
Mybatis.config-location=classpath:mybatis/mybatis-config.xml
Mybatis.type-aliases-package = Org.zhu.mybatis_test.bean

Mybatis-config.xml:
<?xml version= "1.0" encoding= "UTF-8"?> <!
DOCTYPE configuration Public "-//mybatis.org//dtd Config 3.0//en" "Http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>

    <settings>
        <setting name= "Mapunderscoretocamelcase" value= "true"/ >
    </settings>

    <!--set Interceptor-->
    <plugins>
        <plugin interceptor= " Org.zhu.mybatis_test. Pageinterceptor ">
            <property name=" dialect "value=" MySQL "/>
        </plugin>
    </plugins >


</configuration>


two. To achieve
1. General Ideas
Spring Data Jpa pagination is easy

You only need to pass the Pageable object each time you query, you can return the paging information: "Content": {}, "last": false, "TotalPages": 2, "totalelements": 21, "Size": "Number": 0, "sort": null, "A": true, "numberofelements": 20

The pagination for this plugin looks like this:





Through the introduction of the custom Pageable object, dynamically for the corresponding SQL statement plus limit XX,XX to achieve physical paging, and automatically query the total number of paging, dynamic join
into a custom Pageable object, and then returns the list of queries, manually adding the returned content to the custom Pageable object.
2. Implement MyBatis Plug-in Interceptor
If you want to implement some of the behavior, so that the whole page of paging automation run, then you need to mapper the corresponding method of execution, intercept and modify the default behavior
This time you need to manually implement the MyBatis plug-in interceptor.
From official introduction of Plug-ins: MyBatis allows you to intercept calls at a point in the execution of a mapped statement.
Link: http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins
MyBatis can intercept some of the 4 behaviors that sqlsession performs (sorted in order): Executor->statementhandler->parameterhandler-> Resultsethandler
4 large behavior can refer to blog:http://blog.csdn.net/ykzhen2015/article/details/50315027 plug-in principle reference blog:http://blog.csdn.net/ abcd898989/article/details/51244351
First, according to the official website, let's write a simple interceptor:
Import Org.apache.ibatis.executor.statement.StatementHandler;
Import org.apache.ibatis.plugin.*;
Import java.sql.Connection;
Import java.util.Properties;

/**
 * @author yingzhi Zhu
 * Date 2018/1/19.
 * *
@Intercepts ({@Signature (type = Statementhandler.class, method = "Prepare", args = {Connection.class, INTEGER.CLA SS})}) Public
class Pageinterceptor implements Interceptor {

    @Override the public
    Object intercept ( Invocation invocation) throws Throwable {
        System.out.println ("intercepted");
        return Invocation.proceed ();
    }
    @Override Public
    Object Plugin (object target) {return
        plugin.wrap (target, this);
    }
    @Override public
    void SetProperties (Properties properties) {
    }
}
Run the program, perform a mapper operation, has taken effect.

But there's a slight difference between the example and the website.
@Intercepts ({@Signature (
  type= executor.class, method
  = "Update",
  args = {Mappedstatement.class, Object.class})})
The contents of the @Signature are different, the type is the blocked interface method is the args in the interface is the parameter in the method.
The point to be raised here is that the plug-in interceptor can only intercept a method in the following 4 interfaces that can be discovered through requirements, and the functionality that needs to be implemented
1. Dynamic modification of SQL statements
2. Dynamic execution to find the total number of pages of the SQL statement
3. Dynamic access to the parameters passed over
Then it should be done in the interception method.
1. You can get a database connection in a blocking method and perform a separate database operation
2. Can get the original SQL statement
3. Dynamic modification of the original SQL statement
4. Can get the parameters in the passed method
satisfies the condition and the best is the prepare method in the statement interface


In this interface, the method parameter takes a database connection object and can obtain Boundsql and Parameterhander objects. The SQL statement in Mapper is
stored in the Boundsql, the mapper parameter information is stored in the Parameterhander.



    @Override public
    Object intercept (invocation invocation) throws Throwable {
        //Get database connection
        Connection Connection = (connection) Invocation.getargs () [0];
        Gets the Blocked Statementhandler interface sample Object
        Statementhandler Statementhandler = (statementhandler) invocation.gettarget ();
        Gets the object that stores the instance of the SQL statement in MyBatis
        boundsql boundsql = Statementhandler.getboundsql ();
        Gets the object
        parameterhandler Parameterhandler = Statementhandler.getparameterhandler () for a parameter instance in the store mapper in MyBatis.
        return Invocation.proceed ();
    }
The Intercept method is to perform an additional operation before the interception method is executed, and the instance passed over invocation is obtained through the reflection mechanism in @signature
An instance of a class, method, or argument that is intercepted. Finally, we need to use the Invocation.procceed () method to implement the original method, so that mybatis back to his life cycle by default
Method of implementation.
The above code gets the instance object of the database connection SQL statement and parameters. Of course, there's one of the biggest jobs in this section. Not all of the methods we can intercept, we only intercept a specific method: parameters with a custom
Pageable the method of the object.
  /** * Set which MyBatis objects need to be intercepted by the plugin * @param target MyBatis Object * @return/@Override public Object P
            Lugin (object target) {///block only methods in Statementhandler with Pageable objects in parameters (target instanceof Statementhandler) {
            if (getpageable (statementhandler) target)!= null) {return Plugin.wrap (target, this);
    }//release return target; The Pageable object parameter passed in/** * Fetch method does not return NULL * @param statementhandler * * @return * * Private PAGEABL E getpageable (Statementhandler statementhandler) {//Get passed Parameter object o = Statementhandler.getparameterha
        Ndler (). Getparameterobject ();
        Mode one if single only one parameter if (o instanceof pageable) {return (pageable) O; 
                //Mode Two if more than one argument is encapsulated into the map if (o instanceof HashMap) {for (Object value: (HASHMAP) O). VALUES ()) { if (value instanceof pageable) {return (Pageable) value;
    }} return null; }

3. Add limit to the original SQL statement
    /**
     * Set Paging SQL statement
     * @param boundsql
     * @param pageable
    /private void Setsqlstatement (Boundsql Boundsql,pageable pageable) {
        int start = (Pageable.getpage ()-1) *pageable.getsize ();
        int size = Pageable.getsize ();
        String pagingsql = boundsql.getsql () + "Limit" + Start + "," + size;
        Method 1: Use the MyBatis native method to force the SQL statement to be written to the field in Boundsql private final String sql
        metaobject metaobject =
                    Metaobject.forobject (Boundsql, systemmetaobject.default_object_factory,
                            systemmetaobject.default_object_ Wrapper_factory,new defaultreflectorfactory ());
        Metaobject.setvalue ("SQL", Pagingsql);
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.