Mybatis实现分页功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40883132/article/details/82817614

由于我之前有一篇博客写到实现分页功能,简单的分页功能,但是如果我们有多个页面,就需要每一个页面都写一个这个麻烦的代码,显得非常的愚笨。于是出现了Mybatis分页,有点类似于Spring的AOP(这里不讲解)。

首先,我们是想一个特定查询的语句执行的时候需要进行拦截,执行分页的功能。

一般的步骤是写一个拦截类,然后注册。

我们需要一个类,这里叫做PageInterceptor

package com.interceptor;

import main.entity.Page;
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 java.sql.ResultSet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Map;
import java.util.Properties;

/**
 * @program: Tradingplatform
 * @description:分页拦截器
 * @author: Robert_Wang
 * @create: 2018-09-16 19:46
 **/
//拦截的类+方法(防止重载,需加上参数)
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class PageInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取拦截目标
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        //元对象, 由于我们想要获得一个 protected ResultMap,所以用反射来实现
        //将元对象方便我们访问属性
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY);
        //按照OGNL表达式 访问属性
        //获取与xml所对应的关键信息
            MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
            //配置文件中sql的id, 即 queryListByPage
            String id =  mappedStatement.getId();
            //正则表达式 .+ 至少出现一个字符 $是结束符
            if(id.matches(".+ByPage$")){
                BoundSql boundSql = statementHandler.getBoundSql();
                String sql = boundSql.getSql();
                String countSql = "select count(*) from (" + sql + ")a";
                Connection connection = (Connection)invocation.getArgs()[0];
                PreparedStatement countStatement = connection.prepareStatement(countSql);
                ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
                parameterHandler.setParameters(countStatement);
                ResultSet rs =  countStatement.executeQuery();
                Map<?,?> parameter = (Map<?,?>)boundSql.getParameterObject();
                Page page = (Page)parameter.get("page");
                if(rs.next()){
                    page.setTotalNumber(rs.getInt(1));
                }
                String pageSql = sql + " limit " + page.getDbIndex() + "," + page.getDbNumber();
                //修改sql语句
                metaObject.setValue("delegate.boundSql.sql",pageSql);

        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        //返回代理类
        return Plugin.wrap(o,this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

plugin方法是返回一个代理过的类,参数是代理的对象。

setProperties是用于设置参数。是在进行注册的时候设置的参数。

interceptor是拦截的过程,也是本次的核心。

        我们先明确目的:在查询语句的PreparedStatement前进行拦截,那么我们就要

        获得xml中的sql语句, 执行相关的操作(查询总条数、计算多少个页面、等)

然后我们再细分这个过程慢慢解决。

拦截的类前面加一个注解,表示拦截该类时签有类型、方法的类,参数就是区分重载函数。

      首先获取拦截目标 -->获取sql语句-->>进行sql相关的操作

再进行细分;

首先获取拦截目标:StatementHandler

获取sql语句之前需要在xml获取,于是需要MappedStatement这个类,这个类是需要元对象MetaObject来获取的,

而元对象是需要StatementHandler。

于是就关联起来了,其实用到的就是StatementHandler MetaObject  StatementHandler最主要的三个类。

     然后就是SQL操作了:先判断拦截的SQL是不是我们想要的SQL,如果是,再查询条数,设置参数值即可。

再进行细分:
查询条数:拼接SQL语句-->获取连接-->预编译-->参数设置。

其他的细枝末节就这样分了,下面不再详细分了。

猜你喜欢

转载自blog.csdn.net/qq_40883132/article/details/82817614