注:mapper中的方法必须以ByPage结尾,例:selectByPage();
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;
//@Signature:是对插件需要拦截的对象进行签名,type:表示要拦截的类型,method表示拦截类中的方法,args:是需要的参数,
//这里的参数在后面也可以获取到.statementHandler:数据库会话器专门用于处理数据库会话:statement的执行操作,是一个接口
@Component
@Intercepts(@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class,Integer.class}
))
public class PagePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
/**
* 1.拿到原始sql
* 2.修改原始sql,增加分页 select * from user limit 0,10
* 3.执行jdbc去查询总数
*/
//从invocation中拿到StatementHandler对象
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
//拿到原始sql
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
System.out.println("原始sql为:"+sql);
//分页参数
Object parameterObject = boundSql.getParameterObject();
//statementHandler 转换成metaObject
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
//获取mapper接口中的方法名称 selectByPage
String mapperMethodName = mappedStatement.getId();
if(mapperMethodName.matches(".*ByPage$")){
Map<String,Object> params = (Map<String,Object>)parameterObject;
PageInfo pageInfo = (PageInfo) params.get("page");//map.put("page",pageInfo);
String countSql = "select count(0) from ("+sql+") a";
System.out.println("查询总数的sql:"+countSql);
//执行jdbc操作
Connection connection = (Connection) invocation.getArgs()[0];
PreparedStatement countStatement = connection.prepareStatement(countSql);
ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
parameterHandler.setParameters(countStatement);
ResultSet resultSet = countStatement.executeQuery();
if(resultSet.next()){
pageInfo.setTotalNumber(resultSet.getInt(1));
}
resultSet.close();
countStatement.clearParameters();
String pageSql = generaterPageSql(sql,pageInfo);
System.out.println("分页sql为:"+pageSql);
metaObject.setValue("delegate.boundSql.sql",pageSql);
}
//将执行流程交给mybatis继续去执行
return invocation.proceed();
}
//根据原始sql生成limit分页sql
public String generaterPageSql(String sql,PageInfo pageInfo){
StringBuffer sb = new StringBuffer();
sb.append(sql);
sb.append(" limit "+pageInfo.getStartIndex()+" , "+pageInfo.getTotalSelect());
return sb.toString();
}
/**
* 将自定义的插件放入到mybatis中去执行
* @param o
* @return
*/
@Override
public Object plugin(Object o) {
return Plugin.wrap(o,this);
}
@Override
public void setProperties(Properties properties) {
}
}
public class PageInfo implements Serializable {
private static final long serialVersionUID = 1L;
private int totalNumber;//当前表中总条目数
private int currentPage;//当前页的位置
private int totalPage;//总页数
private int pageSize = 3;//每页条目数
private int startIndex;//检索的起始位置
private int totalSelect;//检索的总条目数
//其他get set方法去掉了
public void setTotalNumber(int totalNumber) {
this.totalNumber = totalNumber;
this.count();
}
//计算
private void count() {
int totalPageTemp = this.totalNumber/this.pageSize;
int plus = (this.totalNumber%this.pageSize) == 0 ? 0 : 1;
totalPageTemp +=plus;
if(totalPageTemp<=0){
totalPageTemp =1;
}
this.totalPage = totalPageTemp;//总页数
if(this.totalPage < this.currentPage){
this.currentPage = this.totalPage;
}
if(this.currentPage<1){
this.currentPage = 1;
}
this.startIndex = (this.currentPage-1)*this.pageSize;//起始位置等于之前所有页面数乘以页面大小
this.totalSelect = this.pageSize;//检索数量等于页面大小
}
}