MyBatis-plus分页插件------笔者还是不建议使用分页插件

MyBatis-plus分页插件

    • 1、分页对象
    • 2、分页插件(其实就是一个拦截器)
    • 3、反射工具
    • 4、配置(主要看plugins)

1、分页对象

package com.dsanjun.common.autopage;

import java.io.Serializable;
import java.util.List;

/**
 * 自动分页对象
 * 
 * @author dyw
 * @date 2019年9月20日
 * @param 
 */
public class AutoPage implements Serializable {
	private static final long serialVersionUID = 2862962633786434439L;
	/**
	 * 每页数据量,默认10条
	 */
	private int pageSize = 10; // 每页显示记录数
	/**
	 * 当前页,默认第一页
	 */
	private int currentPage = 1; // 当前页
	/**
	 * 数据库分页的起始索引位置,这里需要计算
	 */
	private int currentDBIndex;
	/**
	 * 总页数
	 */
	private int totalPage;
	/**
	 * 总记录数
	 */
	private int totalCount;

	/**
	 * 查询到的分页数据
	 */
	private List records;

	public List getRecords() {
		return records;
	}

	public void setRecords(List records) {
		this.records = records;
	}

	public int getTotalPage() {
		if (totalCount % pageSize == 0) {
			totalPage = totalCount / pageSize;
		} else {
			totalPage = totalCount / pageSize + 1;
		}
		return totalPage;
	}

	public int getCurrentPage() {
		if (currentPage <= 0) {
			currentPage = 1;
		}
		if (currentPage > getTotalPage()) {
			currentPage = getTotalPage();
		}
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getCurrentDBIndex() {
		currentDBIndex = (getCurrentPage() - 1) * getCurrentPage();
		return currentDBIndex;
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
}

2、分页插件(其实就是一个拦截器)

package com.dsanjun.common.autopage;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import javax.xml.bind.PropertyException;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;

/**
 * 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。
 * 
 * 
  *  利用拦截器实现Mybatis分页的原理:
 * 1、要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象。
 * 2、Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句是在Statement之前产生的。
 * 3、在Mybatis中Statement语句是通过RoutingStatementHandler对象的prepare方法生成的。
 * 4、拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用StatementHandler对象的prepare方法(即调用invocation.proceed())。
 * 5、在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。
 * 
* * @author dyw * @date 2019年9月20日 * @param */ @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) }) @SuppressWarnings("unchecked") public class AutoPageInterceptor implements Interceptor { private Logger log = LoggerFactory.getLogger(AutoPageInterceptor.class); /** * 数据库类型 */ private String databaseType; /** * 分页Sql标识(Mapper接口分页方法命名要包含该字段,以便分页插件拦截该方法) */ private String pageSqlId; /** * 分页对象接口中的名子(Mapper接口AutoPage参数的名字,要保证你的分页接口的分页对象名和这里保持一致) */ private String autoPageParamName; /** *
	 * 类层级结构:
	 *  StatementHandler 
	 *    ---RoutingStatementHandler
	 *    ---BaseStatementHandler
	 *       ---SimpleStatementHandler
	 *       ---PreparedStatementHandler
	 *       ---CallableStatementHandler 
	 *类的作用:       
	 *   SimpleStatementHandler是用于处理Statement
	 *   PreparedStatementHandler是处理PreparedStatement
	 *   CallableStatementHandler是处理CallableStatement
	 *   
	 * 执行原理:  
	 *   1、Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler
	 *   2、 而在RoutingStatementHandler里面拥有一个 StatementHandler类型的delegate属性
	 *   3、RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler
	 *              (即SimpleStatementHandler、 PreparedStatementHandler或CallableStatementHandler)
	 *   4、在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
	 *   5、我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法, 
	 *                又因为Mybatis只有在建立RoutingStatementHandler的时候是通过Interceptor的plugin方法进行包裹的,
	 *                所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
	 * 
*/ @Override public Object intercept(Invocation ivk) throws Throwable { RoutingStatementHandler statementHandler = (RoutingStatementHandler) PluginUtils.realTarget(ivk.getTarget()); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement"); if (mappedStatement.getId().contains(pageSqlId)) { // 拦截需要分页的SQL BoundSql boundSql = delegate.getBoundSql(); // 分页SQL