mybatis拦截器分页

package com.test.interceptor;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
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.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.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.mysql.jdbc.PreparedStatement;
import com.test.util.Page;

@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }),
        @Signature(method = "query", type = Executor.class, args = {
                MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class }) })
public class StatementHandleInterceptor implements Interceptor {
    public static final String MYSQL = "mysql";
    protected ThreadLocal<Page> pageThreadLocal = new ThreadLocal<Page>();     

    public Object intercept(Invocation invocation) throws Throwable {
        if (invocation.getTarget() instanceof StatementHandler){
            Page<?> page = pageThreadLocal.get();
            if(page==null){
                return invocation.proceed();
            }
            RoutingStatementHandler statementHandler = (RoutingStatementHandler) invocation
                    .getTarget();
            StatementHandler delegate = ReflectUtil.getFieldValue(
                    statementHandler, "delegate");
            BoundSql boundSql = delegate.getBoundSql();
            Connection connection = (Connection) invocation.getArgs()[0];

            if(page.getTotalPage()>-1){
                System.out.println("总页数:"+page.getTotalPage());
            }else{
                Object obj = boundSql.getParameterObject();
                MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
                MappedStatement mappedStatement=(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
                queryTotalRecord(page, obj, mappedStatement, connection);
            }
            String sql = boundSql.getSql();
            String pageSql = buildPageSql(page,sql);
            System.out.println("分页时,生成pageSql:"+pageSql);
            ReflectUtil.setFieldValue((Object)boundSql, "sql",pageSql);
            return invocation.proceed();
        }else{
            Page<?> page = findPageObject(invocation.getArgs()[1]);
            if(page==null){
                System.out.println("没有page参数对象,不是分页查询");
                return invocation.proceed();
            }else{
                System.out.println("检测到page对象!使用分页查询");
            }            

            pageThreadLocal.set(page);
            try{
                return invocation.proceed();
                //可setpage  Results
                /*Object resultObj = invocation.proceed();
                if(resultObj instanceof List){
                    page.setResults((List)resultObj);
                }
                return resultObj;*/

            }finally{
                pageThreadLocal.remove();
            }
        }
    }

     private String buildPageSql(Page page,String sql) {
        // 计算第一条记录的位置,Mysql中记录的位置是从0开始的。
        int offset = (page.getPageNo() - 1) * page.getPageSize();
        return new StringBuilder(sql).append(" limit ").append(offset)
                .append(",").append(page.getPageSize()).toString();
    }    

    /**
     * 判定是否需要分页拦截
     * @param object
     * @return
     */
    private Page<?> findPageObject(Object object) {
        if(object instanceof Page<?>){
            return (Page<?>) object;
        }else if(object instanceof Map){
            for(Object o:((Map<?,?>) object).values()){
                if(o instanceof Page<?>){
                    return (Page<?>) o;
                }
            }
        }
        return null;
    }
    /**
     * 查询总记录数
     * @param page
     * @param obj
     * @param mappedStatement
     * @param connection
     * @throws SQLException
     */
    private void queryTotalRecord(Page<?> page, Object obj,
            MappedStatement mappedStatement, Connection connection) throws SQLException {
        BoundSql boundSql = mappedStatement.getBoundSql(page);
        String sql = boundSql.getSql();
        String countSql = this.buildCountSql(sql);
        System.out.println("分页时,生成countSql:"+countSql);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(),countSql,parameterMappings,obj);
        ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, obj, countBoundSql);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            pstmt = (PreparedStatement) connection.prepareStatement(countSql);
            parameterHandler.setParameters(pstmt);
            rs = pstmt.executeQuery();
            if(rs.next()){
                 long totalRecord = rs.getLong(1);
                 page.setTotalRecord(totalRecord);
            }
        }finally{
            if(rs!=null){
                rs.close();
            }
            if(pstmt!=null){
                pstmt.close();
            }
        }

    }
    /**
     * 构造查询总记录数sql
     * @param sql
     * @return
     */
    private String buildCountSql(String sql) {
        int index = sql.toLowerCase().indexOf("from");
        return "select count(*)"+sql.substring(index);
    }
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {

    }

}

调用

结果:

时间: 2024-10-12 21:16:05

mybatis拦截器分页的相关文章

bean 和 Map 的相互转换(Mybatis 拦截器分页--将Object的参数对象封装到Pager 的params 中)

1 apache 的beanUtils 工具类,只能将Bean 转换成 Map<String,String>类型,不能转换成 Map<String,Object> 2 借助工具类DozerBeanMapper 需要引入的jar 有dozer.jar  此外还包含:slf4j.jar,commons-lang.jar,commons-beanutil.jar, commons-loggin.jar 3 写自定义工具类 import org.dozer.DozerBeanMapper;

Mybatis拦截器介绍及分页插件

1.1    目录 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 1.2     前言 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor

Mybatis拦截器实现分页

本文介绍使用Mybatis拦截器,实现分页:并且在dao层,直接返回自定义的分页对象. 最终dao层结果: public interface ModelMapper { Page<Model> pageByConditions(RowBounds rowBounds, Model record); } 接下来一步一步来实现分页. 一.创建Page对象: public class Page<T> extends PageList<T> { private int page

Mybatis最入门---分页查询(拦截器分页原理及实现)

[一步是咫尺,一步即天涯] 前文,我们演示了物理分页的Sql实现方式,这种方式使得我们每次在编写查询服务时,不断的重复造轮子.这样的代码实现方式就显得十分的笨拙了.本文是Mybatis分页查询的最后一片内容,我们将介绍基于拦截器的,精巧的实现方式.在阅读这篇文章之前,强烈建议各位看官能够先阅读上文.这样就能对下文我们提及的各种对象及他们之间的关系有一个清晰的关系.好了,废话不多讲,开始我们的正文部分吧. 准备工作: a.操作系统 :win7 x64 b.基本软件:MySQL,Mybatis,SQ

Mybatis拦截器介绍

拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor.ReuseExecutor.SimpleExecutor和CachingExecutor.这个时候如果你觉得这几种实现对于Execu

【Mybatis】1、Mybatis拦截器

MyBatis拦截器原理探究 http://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html MyBatis 拦截器 (实现分页功能) http://www.cnblogs.com/jethypc/p/5149183.html 由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理 http://zhangbo-peipei-163-com.iteye.com/blog/2033832 使用方法 https://github.

【Mybatis】1、Mybatis拦截器学习资料汇总

MyBatis拦截器原理探究 http://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html [myBatis]Mybatis中的拦截器 http://blog.csdn.net/moshenglv/article/details/52699976 MyBatis 拦截器 (实现分页功能) http://www.cnblogs.com/jethypc/p/5149183.html 由浅入深分析mybatis通过动态代理实现拦截器(插件

Mybatis 拦截器(二)

Mybatis拦截器介绍 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑.打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor.ReuseExecutor.SimpleExecutor和CachingExecutor.这个时候如果你觉

mybatis拦截器使用

[toc] mybatis拦截器入门 mybatis 拦截器接口Interceptor Interceptor接口,我们通过这个接口可以自定义我们自己的拦截器,从而实现在拦截的时候写上我们自己的一些逻辑.该接口提供了三个方法, 接口介绍: intercept方法: intercept方法是在进行拦截的时候要执行的方法. plugin方法: 该方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理. setProperties方法: mybatis配置文件中co