Mybatis利用拦截器做统一分页
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利用拦截器做统一分页的更多相关文章
- Mybatis拦截器介绍及分页插件
1.1 目录 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 1.2 前言 拦截器的一 ...
- MyBatis实现拦截器分页功能
1.原理 在mybatis使用拦截器(interceptor),截获所执行方法的sql语句与参数. (1)修改sql的查询结果:将原sql改为查询count(*) 也就是条数 (2)将语句sql进行拼 ...
- MyBatis 拦截器 (实现分页功能)
由于业务关系 巴拉巴拉巴拉 好吧 简单来说就是 原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能 现在想要达到效果是 只通过一个方法就可以实现 也 ...
- Mybatis Interceptor 拦截器原理 源码分析
Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最 ...
- Mybatis之拦截器原理(jdk动态代理优化版本)
在介绍Mybatis拦截器代码之前,我们先研究下jdk自带的动态代理及优化 其实动态代理也是一种设计模式...优于静态代理,同时动态代理我知道的有两种,一种是面向接口的jdk的代理,第二种是基于第三方 ...
- mybatis Interceptor拦截器代码详解
mybatis官方定义:MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...
- mybatis定义拦截器
applicationContext.xml <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlS ...
- springboot+springmvc拦截器做登录拦截
springboot+springmvc拦截器做登录拦截 LoginInterceptor 实现 HandlerInterceptor 接口,自定义拦截器处理方法 LoginConfiguration ...
- [Java]利用拦截器和自定义注解做登录以及权限验证
1.自定义注解 需要验证登录的注解 package com.etaofinance.wap.common; import java.lang.annotation.Documented; import ...
随机推荐
- 页面QQ在线咨询、在线交谈代码
页面QQ在线咨询.在线交谈代码 样式一: <a target="blank" rel="nofollow" href="tencent://me ...
- 阿里云阿里免费ssl wap网站在手机微信、手机浏览器无法访问
图片可以访问,样式无法显示 https://css.cnbuses.com/css/wap/gonggong.css 1,怀疑是开了代理访问. 关闭后还是访问空白. 2.在手机浏览器打开,提示该网站的 ...
- Xcode引入了第三方的类库之后真机调试提示莫名其妙的错误
其中的解决方法就是修改Build Setting里面的Build Active Architecture Only(仅仅编译动态代码),将这个里面的值修改为YES即可.
- 基于 HTML5 Canvas 的 Web SCADA 组态电机控制面板
前言 HT For Web 提供完整的基于 HTML5 图形界面组件库.您可以轻松构建现代化的,跨桌面和移动终端的企业应用,无需担忧跨平台兼容性,及触屏手势交互等棘手问题.也可用于快速创建和部署,高度 ...
- Delphi主线程重入而导致程序卡死的解决方案
Delphi的线程可以通过调用AThread.Synchronize(AProc),可以将Proc放入主线程中同步运行,此时AThread将挂起,直到主线程执行完AProc. 如果有BThread,调 ...
- android4.4 重启的开机不播放开机铃声,按power键的开机播放开机铃声
平台:A33Android4.4Linux3.4 功能描述:实现重启的开机不播放开机铃声,按power键的开机播放开机铃声 一,无论关机还是重启都会经过rebootOrShutdown这个方法,在方法 ...
- 【Mac】安装 tesserocr 遇到的一些坑(‘cinttypes' file not found)
问题描述 tesserocr 是 Python 的一个光学字符识别库,它其实是对 tesseract 做的一层 Python API 封装,所以在安装这个库之前我已经用 Homebrew 成功安装好了 ...
- C语言进阶——基本数据类型01
刚开始人们还没有数据类型这个概念,但是人们经常要使用到固定内存大小的内存,这个时候那时的程序员就要记录一段信息在内存中的起始位置和终止位置,很不方便,演变到后来就出现了数据类型这个概念 什莫是数据类型 ...
- 763. Hex Conversion [LintCode naive]
Description Given a decimal number n and an integer k, Convert decimal number n to base-k. 1.0<=n ...
- 【转】ASP.NET 防止同一用户同时登陆
要防止同一用户同时登陆,首页应该记录在线用户的信息(这里与用户名为例),然后判断正在登陆的用户里面是否已存在.在这里使用一个cache存放已经登陆的用户名,但是还有一个问题就是要知道用户是什么时候离开 ...