Mybatis分页实现的方法(拦截器+pageHelper)

一、拦截器实现

1.原理

在mybatis 运行过程中拦截执行对象,获得sql信息,将分页信息添加到sql语句中,然后放行mybatis的执行过程

2.了解一点mybatis源码

首先我们需要明白要拦截的对象是处理对象(Statement),拦截的时机应该是sql执行之前,

所以我们应该拦截的是:
@Intercepts({@Signature(type=StatementHandler.class,method = "prepare",args={Connection.class,Integer.class})})

type 表示需要拦截的类, method 表示需要拦截的方法, args 表示参数

我们这里拦截主要是(其实这里拦截到的是而是RoutingStatementHandler,它会通过判断来决定实例化那个StatementHandler, BaseStatementHandler只是这里Statement的实现类) BaseStatementHandler ,它实现了Statement。 BaseStatementHandler中通过instantiateStatement 方法来获取statement对象,instantiateStatement的具体实现在PreparedStatementHandler。

上面的叙述可能会有偏差,源码的理解有待提高,这里看源码的主要目的是为了清楚sql的具体信息在哪里,比如BaseStatementHandler下的mappedStatement对应的就是mapper 中xml的信息,BoundSql对应一些sql信息。

为了在代码中获取到sql的具体信息我们需要借助MetaObject这个类,它可以使我们不需要写反射代码获取到一些必要的信息。

 

3.具体代码编写过程

首先,将需要分页的方法名以”ByPage“结尾 或者什么标志标记一下,以确保自己能在后面将这些方法过滤出来

然后,编写拦截器:

page类:

public class Page {

    private int totalNumber;

    private int currentPage;

    private int totalPage;

    private int pageNumber = 5;

    //从第几条开始
    private int dbIndex;

    //取几条
    private int dbNumber;

    public void count(){
        int totlaPageTemp = this.totalNumber / this.pageNumber;
        int plus = (this.totalNumber%this.pageNumber)==0?0:1;
        totlaPageTemp += plus;

        if( totlaPageTemp <= 0 ){
            totlaPageTemp = 1;
        }
        this.totalPage = totlaPageTemp;

        if( this.totalPage < this.currentPage ){
            this.currentPage = this.totalPage;
        }

        if( this.currentPage < 1 ){
            this.currentPage = 1;
        }

        this.dbIndex = (this.currentPage-1)*this.pageNumber;
        this.dbNumber = this.pageNumber;
    }

    public int getTotalNumber() {
        return totalNumber;
    }

    public void setTotalNumber(int totalNumber) {
        this.totalNumber = totalNumber;
    }

    public int getCurrentPage() {
        return currentPage;
    }

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

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getPageNumber() {
        return pageNumber;
    }

    public void setPageNumber(int pageNumber) {
        this.pageNumber = pageNumber;
    }

    public int getDbIndex() {
        return dbIndex;
    }

    public void setDbIndex(int dbIndex) {
        this.dbIndex = dbIndex;
    }

    public int getDbNumber() {
        return dbNumber;
    }

    public void setDbNumber(int dbNumber) {
        this.dbNumber = dbNumber;
    }

    @Override
    public String toString() {
        return "Page{" +
                "totalNumber=" + totalNumber +
                ", currentPage=" + currentPage +
                ", totalPage=" + totalPage +
                ", pageNumber=" + pageNumber +
                ", dbIndex=" + dbIndex +
                ", dbNumber=" + dbNumber +
                '}';
    }
}
/**
 * mybatis 分页拦截器
 */
@Intercepts({@Signature(type=StatementHandler.class,method = "prepare",args={Connection.class,Integer.class})})
public class PageInterceptor implements Interceptor {
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler,SystemMetaObject.DEFAULT_OBJECT_FACTORY,SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,new DefaultReflectorFactory());
        /*
        从RoutingStatementHandler中获得处理对象PreparedStatementHandler,从这个对象中获取Mapper中的xml信息
        * */
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        //配置文件中sql语句的id
        String id = mappedStatement.getId();
        //判断是否是需要分页的方法
        if( id.matches(".+ByPage$") ){
            //获得sql的参数信息
            BoundSql boundSql = statementHandler.getBoundSql();
            Map<String, Object> parameter = (Map<String, Object>)boundSql.getParameterObject();
            Page page = (Page)parameter.get("page");
            //原始的sql
            String sql = boundSql.getSql();
            System.out.println("未改造的sql语句:"+sql);
            //组装page中的信息,查询总条数
            String countSql = "select count(*) from ("+sql+")a";
            System.out.println("查询总条数sql语句:"+countSql);
            Connection connection = (Connection)invocation.getArgs()[0];
            PreparedStatement statement = connection.prepareStatement(countSql);
            ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(statement);
            ResultSet rs = statement.executeQuery();
            if( rs.next() ){
                int total = rs.getInt(1);
                page.setTotalNumber(total);
                System.out.println("总条数:"+total);
            }else{
                System.out.println("未查询到数据量");
            }
            page.count();

            //改造后的sql语句
            String pageSql = sql + " limit "+ page.getDbIndex()+" , "+page.getDbNumber();
            System.out.println("改造后的sql语句:"+pageSql);
            metaObject.setValue("delegate.boundSql.sql",pageSql);
        }
        //放行
        return invocation.proceed();
    }

    //被拦截的请求
    public Object plugin(Object o) {
        return Plugin.wrap(o,this);
    }

    public void setProperties(Properties properties) {
        //这里可以拿到配置文件中 plugin 中的propertie的值
    }
}

最后,在配置文件中注册拦截器

    <plugins>
        <plugin interceptor="per.ly.interceptor.PageInterceptor" />
    </plugins>

 

4.总结

使用不够快捷。

 

二、pageHelper

参考自:https://www.cnblogs.com/shanheyongmu/p/5864047.html

出现错误一:https://blog.csdn.net/s592652578/article/details/78179998?locationNum=4&fps=1

出现错误二:https://blog.csdn.net/u011560753/article/details/78750119

1、添加依赖

    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.2</version>
    </dependency>

2、在mybatis配置文件中配置

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
        </plugin>
    </plugins>

3、实现简单分页

PageHelper.startPage(pagenum,pagesize);

4、总结

只能对查询出的结果进行分页,可能无法满足要求。

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值