mybatis利用拦截器做统一分页

查询传递Page参数,或者传递继承Page的对象参数。拦截器查询记录之后,通过改造查询sql获取总记录数。赋值Page对象,返回。

示例项目:https://github.com/windwant/spring-boot-service

https://github.com/windwant/spring-dubbo-service/tree/master/spring-boot-server

拦截器:

package com.xxx;

import com.xxx.Page;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties; /**
*/
@Intercepts({//拦截query查询
@Signature(type=Executor.class,method="query",args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})
})
public class PageIntercept implements Interceptor { public static final Logger logger = LoggerFactory.getLogger(PageIntercept.class); @Override
public Object intercept(Invocation invocation) throws Throwable {
Object parameter = invocation.getArgs()[1];
Object args = invocation.getArgs()[1];
Object returnValue = invocation.proceed();
if(args instanceof Page && ((Page) args).isCount()){
MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
String originalSql = boundSql.getSql().trim();
Object parameterObject = boundSql.getParameterObject();
if(parameterObject instanceof Page){
((Page) parameterObject).setOffset(0);
((Page) parameterObject).setLimit(Integer.MAX_VALUE/((Page) parameterObject).getPage());
} String countSql = "SELECT COUNT(*) FROM (" + originalSql + ") aliasForPage";
Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection(); BoundSql countBS = copyFromBoundSql(mappedStatement, boundSql, countSql);
DefaultParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBS);
PreparedStatement countStmt = connection.prepareStatement(countSql);
parameterHandler.setParameters(countStmt);
ResultSet rs = countStmt.executeQuery();
int total =0;
if (rs.next()) {
total = rs.getInt(1);
}
rs.close();
countStmt.close();
connection.close();
//分页计算
((Page) args).setTotal(total);
} return returnValue;
} private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) {
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
for (ParameterMapping mapping : boundSql.getParameterMappings()) {
String prop = mapping.getProperty();
if (boundSql.hasAdditionalParameter(prop)) {
newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
}
}
return newBoundSql;
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
} @Override
public void setProperties(Properties properties) { } }

数据库配置:

package com.xxx.config;

import javax.sql.DataSource;

import com.xxx.PageIntercept;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; /**
* @description
*/ @Configuration
@MapperScan(basePackages = "com.xxx.dao", sqlSessionFactoryRef = "sqlSessionFactory")
public class DBConfig { private final static Logger logger = LoggerFactory.getLogger(DBConfig.class); @Bean(name = "dataSource")
@ConfigurationProperties(prefix = "datasource.planes")
@Primary
public DataSource dataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "sqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource());
bean.setPlugins(new Interceptor[]{new PageIntercept()});
return bean.getObject();
} @Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
} }  

Page对象:

package com.xxx;

import com.xxx.Constants;

/**
* Created by Administrator on 2018/1/5.
*/
public class Page { private int offset = 0; private int limit = Constants.DEAFULT_PAGE_LIMIT; private int total = 0; private int page = 1; private boolean count = true; public boolean isCount() {
return count;
} public void setCount(boolean count) {
this.count = count;
} public Page(){} public Page(int offset, int limit){
this. offset = offset;
this.limit = limit;
}
public int getPage() {
return page;
} public void setPage(int page) {
this.page = page < 1?1:page;
} public int getOffset() {
return (page - 1) * limit;
} public void setOffset(int offset) {
this.offset = offset;
} public int getLimit() {
return limit;
} public void setLimit(int limit) {
this.limit = limit;
} public int getTotal() {
return total;
} public void setTotal(int total) {
this.total = total;
}
}

  

Mybatis利用拦截器做统一分页的更多相关文章

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

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

  2. MyBatis实现拦截器分页功能

    1.原理 在mybatis使用拦截器(interceptor),截获所执行方法的sql语句与参数. (1)修改sql的查询结果:将原sql改为查询count(*) 也就是条数 (2)将语句sql进行拼 ...

  3. MyBatis 拦截器 (实现分页功能)

    由于业务关系 巴拉巴拉巴拉 好吧 简单来说就是 原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能 现在想要达到效果是 只通过一个方法就可以实现 也 ...

  4. Mybatis Interceptor 拦截器原理 源码分析

    Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最 ...

  5. Mybatis之拦截器原理(jdk动态代理优化版本)

    在介绍Mybatis拦截器代码之前,我们先研究下jdk自带的动态代理及优化 其实动态代理也是一种设计模式...优于静态代理,同时动态代理我知道的有两种,一种是面向接口的jdk的代理,第二种是基于第三方 ...

  6. mybatis Interceptor拦截器代码详解

    mybatis官方定义:MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...

  7. mybatis定义拦截器

    applicationContext.xml <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlS ...

  8. springboot+springmvc拦截器做登录拦截

    springboot+springmvc拦截器做登录拦截 LoginInterceptor 实现 HandlerInterceptor 接口,自定义拦截器处理方法 LoginConfiguration ...

  9. [Java]利用拦截器和自定义注解做登录以及权限验证

    1.自定义注解 需要验证登录的注解 package com.etaofinance.wap.common; import java.lang.annotation.Documented; import ...

随机推荐

  1. linux使用秘钥登录(禁用root密码登录)

    目的:为了巩固线上外网服务器的安全,避免黑客攻击植入木马,初步决定禁用root密码登录(安全强度低),统一使用秘钥登录(4096位长度,安全性较高) 具体操作如下: 一.生成ssh秘钥: ssh-ke ...

  2. Android UI【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】

    http://blog.csdn.net/lnb333666/article/details/8546497 如题,这是公司项目的一个功能模块,先上个效果图: 其次大致说说原理: 1,首先判断输入的字 ...

  3. multiprocessing进程开发RuntimeError

    windows环境下multiprocessing报如下异常信息: RuntimeError: An attempt has been made to start a new process befo ...

  4. BUAA_OO第二单元总结性博客作业——多线程电梯架构

    一.设计策略 在第一次作业时,我刚第一次接触多线程这个东西……于是乎对于第一次VIP直上直下一次只接一个人的电梯,我借鉴了指导书中为我们提供的架构,设计了一个输入线程和一个电梯线程,并设置了一个中间类 ...

  5. iOS背景音乐不自动播放

    iOS 内置浏览器safari不允许自动播放音乐.我们需要通过WeixinJSBridgeReady()函数实现自动触发 document.addEventListener("WeixinJ ...

  6. #leetcode刷题之路27-移除元素

    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度.不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. ...

  7. [原]nginx 一下快一下慢的问题

    在本机用thinkphp建了一个小网站,没任何问题,发布到云空间,就出现访问很慢的情况,而且是一下快一下慢,奇数次快,偶数次慢 换了一台win10的笔记本,情况一样,更新了phpstudy更新了thi ...

  8. Kafka解惑之时间轮 (TimingWheel)

    Kafka中存在大量的延迟操作,比如延迟生产.延迟拉取以及延迟删除等.Kafka并没有使用JDK自带的Timer或者DelayQueue来实现延迟的功能,而是基于时间轮自定义了一个用于实现延迟功能的定 ...

  9. hadoop docker集群搭建

    获取镜像 #本机内 docker pull ubuntu:16.04 编排镜像 启动一个容器 #本机内 docker run -i -t --name master ubuntu:16.04 在容器内 ...

  10. xss:利用编码绕过(新手向)

    当浏览器接受到一份HTML代码后,会对标签之间(<p>xxx</p>等,<script>除外).标签的属性中(<a href='xxxx'>)进行实体字 ...