博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis自定义轻量级分页组件(易集成,易拓展)
阅读量:3927 次
发布时间:2019-05-23

本文共 6437 字,大约阅读时间需要 21 分钟。

Mybatis自定义轻量级分页组件(易集成,易拓展)

其实github有一个叫做PageHelper的开源分页组件,我也用过,封装的还可以。只是感觉他的量级偏重,其实很多参数,都是我们开发中不需要的参数,而且它的获取分页信息方式是通过构造方法,不是很优雅。所以我在查阅完他的源码后,结合自己的需求,实现了一个轻量级,便携式的分页组件SmallPage

在这里插入图片描述

SmallPage

轻量级分页组件,基于入参类型

核心依赖

org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0

功能描述

  • 自动拦截进行分页
  • 基于Dao层方法入参类型
  • 自动count总条数

核心类 - PageInterceptorPlugin

  • 使用方式,只需将Dao查询方法的入参Bean继承于PageWrapperBean,设定Page对象则可以实现分页,分页完成后的信息也保存在Page对象中
  • 入参类型可以parameterType 定义,也可以@Param("")传入,多个入参时,只要其中一个入参类型为PageWrapperBean的上转类型,就可以实现分页
  • 入参类型不为PageWrapperBean的上转类型时,直接推进拦截链

实现方式

现在java的持久层框架大多基于Mybatis的框架,所以实现分页的思路,也就拦截待执行的sql进行追加Limt限定,来实现分页。

/** * @author machenike */@Intercepts(@Signature(type = StatementHandler.class,method = "prepare",args={
Connection.class,Integer.class}))public class PageInterceptorPlugin implements Interceptor {
private static final String META_OBJECT_KEY_SQL_ID = "delegate.mappedStatement.id"; private static final String META_OBJECT_KEY_BOUND_SQL = "delegate.boundSql.sql"; private static final Logger logger = LoggerFactory.getLogger(PageInterceptorPlugin.class); @Override public Object intercept(Invocation invocation) throws Throwable {
//获取命令handler取得 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); //获取入参handler ParameterHandler parameterHandler = statementHandler.getParameterHandler(); //获取参数对象 Object parameterObject = parameterHandler.getParameterObject(); PageBean pageBean = getPageBean(parameterObject); ThreadLocal threadLocal = new ThreadLocal(); if(pageBean!=null) {
logger.debug("parameter type match,start intercept"); //获取meta对象取得 MetaObject metaObject = MetaObject.forObject( statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); //获取当前sqlId String sqlId = (String)metaObject.getValue(META_OBJECT_KEY_SQL_ID); //原来应该执行的sql吧 String sql = statementHandler.getBoundSql().getSql(); logger.debug("-originSql:" + sql); Connection connection = (Connection) invocation.getArgs()[0]; String countSql = bulidCountSql(sql); logger.debug("-countSql:" + countSql); //渲染参数 PreparedStatement preparedStatement = connection.prepareStatement(countSql); //条件交给mybatis parameterHandler.setParameters(preparedStatement); //让mybatis执行这个sql ResultSet resultSet = preparedStatement.executeQuery(); int count = 0; if (resultSet.next()) {
count = resultSet.getInt(1); } resultSet.close(); preparedStatement.close(); //limit 1 ,10 十条数据 总共可能有100 count 要的是 后面的100 pageBean.setTotal(count); //拼接分页语句(limit) 并且修改mysql本该执行的语句 String pageSql = buildPageSql(pageBean, sql); logger.debug("-pageSql:" + pageSql); //重新绑定分页sql metaObject.setValue(META_OBJECT_KEY_BOUND_SQL, pageSql); } //推进拦截器调用链 return invocation.proceed(); } /** * 入参对象中取得分页对象 * @param o * @return */ private PageBean getPageBean(Object o){
PageWrapperBean pageWrapperBean = null; PageBean pageBean = null; //类型判断 //入参为Map 上转类型 if(o instanceof Map){
//迭代Map Map
paramMap = (Map
) o; Set
keySet = paramMap.keySet(); for(String key:keySet){
Object valueObject = paramMap.get(key); if(valueObject instanceof PageWrapperBean){
pageWrapperBean = (PageWrapperBean) valueObject; break; } } //入参为 PageWrapperBean 上转类型 } else if(o instanceof PageWrapperBean){
pageWrapperBean = (PageWrapperBean) o; } pageBean = pageWrapperBean.getPage(); return pageBean; } /** * 构建记录条数countSql * @param originSql * @return */ private String bulidCountSql(String originSql){
//优化一下就是讲select 到from 之间的字符串替换为 count(1) 即可,这里仅为了方便 String countSql = "select count(1) from ("+originSql+") a"; return countSql; } /** * 构建分页sql * @param pageBean * @param originSql * @return */ private String buildPageSql(PageBean pageBean,String originSql){
//拼接分页语句(limit) 并且修改mysql本该执行的语句 String pageSql = originSql+" limit "+pageBean.getStart()+","+pageBean.getLimit(); return pageSql; }}

所有的分页都是PageInterceptorPlugin,因为传入的分页信息都会封装到pageWrapperBean 当中的page对象中,同时page对象也是前端传输分页信息。本来就请求的当前线程所持有,完全不用考虑线程安全,不需要采用PageHelper中ThreadLocal去保存分页信息。

拦截StatementHandler中从StatementHandler取出原始的查询sql,通过ParameterHandler 获取分页参数。
然后将原始的sql通过上述代码中buildPageSql方法进行构建分页sql

/**     * 自动运算相关数值     */    public void autoCount(){
if(limit!=null&&limit>0&&total!=null){
pageCount = total/limit+1; } if(limit!=null&&limit>0&&currentPage>=1) {
start = (currentPage - 1) * limit; } }

我将这个方法放入了,page对象的set方法中,一旦有分页参数变化,分页信息就会有所变化。

satrt的起始的索引的运算公式就是

index = (currentPage - 1) * limit

当前页-1*limit

获取记录总条数的sql通上述的bulidCountSql去构建。

“select count(1) from (”+originSql+") a";

最后使用preparedStatement这个命令对象完成查询,将返回的分页参数,设置到page对象中。

最后在外部使用getPage()方法既可以拿到所有的分页信息。

使用方式

入参对象使用类继承的方式

public class TestEntity extends PageWrapperBean {
private Integer id; private String text; }

分页使用方式

TestEntity testEntity =  new TestEntity();        PageBean pageBean = new PageBean();        pageBean.setCurrentPage(1);        pageBean.setLimit(10);        //设定分页参数        testEntity.setPage(pageBean);        //开始查询        testMapper.select(testEntity);        //取得分页信息        PageBean pageInfo = testEntity.getPage();

入参对象使用@Param 这种Map形式的

List
query(@Param("page")PageWrapperBean pageWrapperBean);

分页使用方式

PageBean pageBean = new PageBean();        pageBean.setCurrentPage(1);        pageBean.setLimit(10);        //设定分页参数        PageWrapperBean pageWrapperBean = new PageWrapperBean(pageBean);        //开始查询        testMapper.query(pageWrapperBean);        //取得分页信息        PageBean pageInfo = pageWrapperBean.getPage();    }

最后附上源码地址,后续还继续优化更新

转载地址:http://mhugn.baihongyu.com/

你可能感兴趣的文章
Spring Security 3 用户信息的问题
查看>>
SpringMVC 过滤器Filter使用解析
查看>>
SpringMVC中使用Interceptor拦截器
查看>>
send email Java发送邮件
查看>>
Java mail 邮箱发送
查看>>
spring有三种启动方式
查看>>
大型电子商务网站架构
查看>>
小型电子商务网站设计原则
查看>>
大型Java多用户商城系统设计开发的心得和困难
查看>>
CGLib与JDK的动态代理
查看>>
Java单元测试(Junit+Mock+代码覆盖率)
查看>>
怎样使用 Junit Framework 进行单元测试的编写
查看>>
MAVEN常用命令+基本配置详解 2015
查看>>
java:快速文件分割及合并
查看>>
redis 学习笔记(1)-编译、启动、停止
查看>>
redis 学习笔记(2)-client端示例代码
查看>>
redis 学习笔记(3)-master/slave(主/从模式)
查看>>
redis 学习笔记(4)-HA高可用方案Sentinel配置
查看>>
redis 学习笔记(5)-Spring与Jedis的集成
查看>>
nginx学习(1):编译、安装、启动
查看>>