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) { } }

调用

结果:

mybatis拦截器分页的更多相关文章

  1. Mybatis拦截器实现分页

    本文介绍使用Mybatis拦截器,实现分页:并且在dao层,直接返回自定义的分页对象. 最终dao层结果: public interface ModelMapper { Page<Model&g ...

  2. Mybatis拦截器介绍及分页插件

    1.1    目录 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 1.2     前言 拦截器的一 ...

  3. MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允 ...

  4. Mybatis拦截器介绍

    拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法.Mybatis拦截器设计的一个初 ...

  5. 数据权限管理中心 - 基于mybatis拦截器实现

    数据权限管理中心 由于公司大部分项目都是使用mybatis,也是使用mybatis的拦截器进行分页处理,所以技术上也直接选择从拦截器入手 需求场景 第一种场景:行级数据处理 原sql: select ...

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

    MyBatis拦截器原理探究 http://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html [myBatis]Mybatis中的拦截器 ...

  7. spring boot 实现mybatis拦截器

    spring boot 实现mybatis拦截器 项目是个报表系统,服务端是简单的Java web架构,直接在请求参数里面加了个query id参数,就是mybatis mapper的query id ...

  8. 【公众号转载】MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允 ...

  9. mybatis拦截器使用

    目录 mybatis 拦截器接口Interceptor spring boot + mybatis整合 创建自己的拦截器MyInterceptor @Intercepts注解 mybatis拦截器入门 ...

随机推荐

  1. c语言栈的链表实现

    #include <stdio.h> #include <stdlib.h> #include"PublicDS.h" typedef int ElemTy ...

  2. JS的运算问题……

    在公司实习期间,发现了一个JS很奇怪的问题. 今天在这里来探讨一下 第一个问题 在生活中或者其他语言中一般相加是这样的:0.1+0.2=0.3; 但在JS中却是这样:0.1+0.2=0.3000000 ...

  3. .NET基础——运算符

    这一篇我们来讲解C#中的运算符 1. C#中的算术运算符 5个算数运算符:+  -  *  /  %     它们都是二元运算符,*  /  % 的运算优先级相同,并且高于 +  - ,+  - 的运 ...

  4. rabbitMQ 安装 could not set correct interactive mode

    安装rabbit mq 提示下面错误 其他信息: 执行错误:C:\Program Files\erl6.0\erts-6.0\bin\erlsrv: Warning, could not set co ...

  5. 【完全背包】HDU 1284 钱币兑换问题

    Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法.请你编程序计算出共有多少种兑法. Input 每行只有一个正整数N,N小于32768. Out ...

  6. 基于DDD的.NET项目搭建

    第一次写博客有点小激动,废话不多说先上图: 01_Client:存放UI相关的项目,比如ASP.NET MVC或者相关的Web Model及View Model项目. 02_Hosting:存放与Se ...

  7. 【NOIP2013】Day2不完全题解+代码

    T1 直接递归区间,从1-n开始,找到这个区间中的最小值然后将区间里的所有值都减去这个最小值 以被减去最小值之后的零点为分段分别递归处理即可. #include <algorithm> # ...

  8. js导航栏样式变换

    <script type="text/javascript"> $(function(){ var lis = $(".submenu").chil ...

  9. 国内首家MR头显公司于CES惊艳亮相

    在刚刚过去的CES2017大会上,我们看到了许多较为优秀的VR产品,而在这里面,有一家名不见经传的中国公司易瞳发布了一款兼具VR和AR功能的头显VMG-MARK.它的外观与联想VR和骁龙VR820等产 ...

  10. webpack + vue最佳实践

    webpack + vue最佳实践 我的原文地址:http://www.xiaoniuzai.cn/2016/10/04/webpack%20+%20vue%E6%9C%80%E4%BD%B3%E5% ...