上一篇文章里已经讲到了mybatis与spring MVC的集成,并且做了一个列表展示,显示出所有article 列表,但没有用到分页,在实际的项目中,分页是肯定需要的。而且是物理分页,不是内存分页。对于物理分页方案,不同的数据库,有不同的实现方法,对于mysql 来说 就是利用
limit offset,pagesize 方式来实现的。oracle 是通过rownum 来实现的,如果你熟悉相关数据库的操作,是一样的很好扩展,本文以mysql 为例子来讲述.先看一下效果图(源代码在文章最后提供下载):



实现mybatis 物理分页,一个最简单的方式是,是在你的mapper的SQL语句中直接写类似如下方式 :

 程序代码


<select id="getUserArticles" parameterType="Your_params" resultMap="resultUserArticleList">

       select user.id,user.userName,user.userAddress,article.id aid,article.title,article.content from user,article

              where user.id=article.userid and user.id=#{id} limit #{offset},#{pagesize}

    </select>

请注意这里的 parameterType 是你传入的参数类,或者map ,里面包含了offset,pagesize ,和其他你需要的参数,用这种方式,肯定可以实现分页。这是简单的一种方式。但更通用的一种方式是用 mybatis 插件的方式. 参考了网上的很多资料 ,mybatis plugin 方面的资料。写自己的插件.

 程序代码


package com.yihaomen.util;



import java.lang.reflect.Field;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.List;

import java.util.Map;

import java.util.Properties;



import javax.xml.bind.PropertyException;



import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;

import org.apache.ibatis.executor.ErrorContext;

import org.apache.ibatis.executor.Executor;

import org.apache.ibatis.executor.ExecutorException;

import org.apache.ibatis.executor.statement.BaseStatementHandler;

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.mapping.ParameterMode;

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.property.PropertyTokenizer;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.ResultHandler;

import org.apache.ibatis.session.RowBounds;

import org.apache.ibatis.type.TypeHandler;

import org.apache.ibatis.type.TypeHandlerRegistry;



@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })

public class PagePlugin implements Interceptor {



    private static String dialect = "";

    private static String pageSqlId = "";



    @SuppressWarnings("unchecked")

    public Object intercept(Invocation ivk) throws Throwable {



        if (ivk.getTarget() instanceof RoutingStatementHandler) {

            RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk

                    .getTarget();

            BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper

                    .getValueByFieldName(statementHandler, "delegate");

            MappedStatement mappedStatement = (MappedStatement) ReflectHelper

                    .getValueByFieldName(delegate, "mappedStatement");



            if (mappedStatement.getId().matches(pageSqlId)) {

                BoundSql boundSql = delegate.getBoundSql();

                Object parameterObject = boundSql.getParameterObject();

                if (parameterObject == null) {

                    throw new NullPointerException("parameterObject error");

                } else {

                    Connection connection = (Connection) ivk.getArgs()[0];

                    String sql = boundSql.getSql();

                    String countSql = "select count(0) from (" + sql + ") myCount";

                    System.out.println("总数sql 语句:"+countSql);

                    PreparedStatement countStmt = connection

                            .prepareStatement(countSql);

                    BoundSql countBS = new BoundSql(

                            mappedStatement.getConfiguration(), countSql,

                            boundSql.getParameterMappings(), parameterObject);

                    setParameters(countStmt, mappedStatement, countBS,

                            parameterObject);

                    ResultSet rs = countStmt.executeQuery();

                    int count = 0;

                    if (rs.next()) {

                        count = rs.getInt(1);

                    }

                    rs.close();

                    countStmt.close();



                    PageInfo page = null;

                    if (parameterObject instanceof PageInfo) {

                        page = (PageInfo) parameterObject;

                        page.setTotalResult(count);

                    } else if(parameterObject instanceof Map){

                        Map<String, Object> map = (Map<String, Object>)parameterObject;

                        page = (PageInfo)map.get("page");

                        if(page == null)

                            page = new PageInfo();

                        page.setTotalResult(count);

                    }else {

                        Field pageField = ReflectHelper.getFieldByFieldName(

                                parameterObject, "page");

                        if (pageField != null) {

                            page = (PageInfo) ReflectHelper.getValueByFieldName(

                                    parameterObject, "page");

                            if (page == null)

                                page = new PageInfo();

                            page.setTotalResult(count);

                            ReflectHelper.setValueByFieldName(parameterObject,

                                    "page", page);

                        } else {

                            throw new NoSuchFieldException(parameterObject

                                    .getClass().getName());

                        }

                    }

                    String pageSql = generatePageSql(sql, page);

                    System.out.println("page sql:"+pageSql);

                    ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql);

                }

            }

        }

        return ivk.proceed();

    }



    private void setParameters(PreparedStatement ps,

            MappedStatement mappedStatement, BoundSql boundSql,

            Object parameterObject) throws SQLException {

        ErrorContext.instance().activity("setting parameters")

                .object(mappedStatement.getParameterMap().getId());

        List<ParameterMapping> parameterMappings = boundSql

                .getParameterMappings();

        if (parameterMappings != null) {

            Configuration configuration = mappedStatement.getConfiguration();

            TypeHandlerRegistry typeHandlerRegistry = configuration

                    .getTypeHandlerRegistry();

            MetaObject metaObject = parameterObject == null ? null

                    : configuration.newMetaObject(parameterObject);

            for (int i = 0; i < parameterMappings.size(); i++) {

                ParameterMapping parameterMapping = parameterMappings.get(i);

                if (parameterMapping.getMode() != ParameterMode.OUT) {

                    Object value;

                    String propertyName = parameterMapping.getProperty();

                    PropertyTokenizer prop = new PropertyTokenizer(propertyName);

                    if (parameterObject == null) {

                        value = null;

                    } else if (typeHandlerRegistry

                            .hasTypeHandler(parameterObject.getClass())) {

                        value = parameterObject;

                    } else if (boundSql.hasAdditionalParameter(propertyName)) {

                        value = boundSql.getAdditionalParameter(propertyName);

                    } else if (propertyName

                            .startsWith(ForEachSqlNode.ITEM_PREFIX)

                            && boundSql.hasAdditionalParameter(prop.getName())) {

                        value = boundSql.getAdditionalParameter(prop.getName());

                        if (value != null) {

                            value = configuration.newMetaObject(value)

                                    .getValue(

                                            propertyName.substring(prop

                                                    .getName().length()));

                        }

                    } else {

                        value = metaObject == null ? null : metaObject

                                .getValue(propertyName);

                    }

                    TypeHandler typeHandler = parameterMapping.getTypeHandler();

                    if (typeHandler == null) {

                        throw new ExecutorException(

                                "There was no TypeHandler found for parameter "

                                        + propertyName + " of statement "

                                        + mappedStatement.getId());

                    }

                    typeHandler.setParameter(ps, i + 1, value,

                            parameterMapping.getJdbcType());

                }

            }

        }

    }





    private String generatePageSql(String sql, PageInfo page) {

        if (page != null && (dialect !=null || !dialect.equals(""))) {

            StringBuffer pageSql = new StringBuffer();

            if ("mysql".equals(dialect)) {

                pageSql.append(sql);

                pageSql.append(" limit " + page.getCurrentResult() + ","

                        + page.getShowCount());

            } else if ("oracle".equals(dialect)) {

                pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");

                pageSql.append(sql);

                pageSql.append(")  tmp_tb where ROWNUM<=");

                pageSql.append(page.getCurrentResult() + page.getShowCount());

                pageSql.append(") where row_id>");

                pageSql.append(page.getCurrentResult());

            }

            return pageSql.toString();

        } else {

            return sql;

        }

    }



    public Object plugin(Object arg0) {

        // TODO Auto-generated method stub

        return Plugin.wrap(arg0, this);

    }



    public void setProperties(Properties p) {

        dialect = p.getProperty("dialect");

        if (dialect ==null || dialect.equals("")) {

            try {

                throw new PropertyException("dialect property is not found!");

            } catch (PropertyException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

        pageSqlId = p.getProperty("pageSqlId");

        if (dialect ==null || dialect.equals("")) {

            try {

                throw new PropertyException("pageSqlId property is not found!");

            } catch (PropertyException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    }



}

此插件有两个辅助类:PageInfo,ReflectHelper,你可以下载源代码参考。

写了插件之后,当然需要在 mybatis 的配置文件Configuration.xml 里配置这个插件

 程序代码
   

    <plugins>

        <plugin interceptor="com.yihaomen.util.PagePlugin">

            <property name="dialect" value="mysql" />

            <property name="pageSqlId" value=".*ListPage.*" />

        </plugin>

    </plugins>

请注意,这个插件定义了一个规则,也就是在mapper中sql语句的id 必须包含ListPage才能被拦截。否则将不会分页处理.



插件写好了,现在就可以在 spring mvc 中的controller 层中写一个方法来测试这个分页:

 程序代码


@RequestMapping("/pagelist")

    public ModelAndView pageList(HttpServletRequest request,HttpServletResponse response){

        int currentPage = request.getParameter("page")==null?1:Integer.parseInt(request.getParameter("page"));

        int pageSize = 3;

        if (currentPage<=0){

            currentPage =1;

        }

        int currentResult = (currentPage-1) * pageSize;

        

        System.out.println(request.getRequestURI());

        System.out.println(request.getQueryString());

        

        PageInfo page = new PageInfo();

        page.setShowCount(pageSize);

        page.setCurrentResult(currentResult);

        List<Article> articles=iUserOperation.selectArticleListPage(page,1);

        

        System.out.println(page);

        

        int totalCount = page.getTotalResult();

        

        int lastPage=0;

        if (totalCount % pageSize==0){

            lastPage = totalCount % pageSize;

        }

        else{

            lastPage =1+ totalCount / pageSize;

        }

        

        if (currentPage>=lastPage){

            currentPage =lastPage;

        }

        

        String pageStr = "";



        pageStr=String.format("<a href=\"%s\">上一页</a>    <a href=\"%s\">下一页</a>",

                        request.getRequestURI()+"?page="+(currentPage-1),request.getRequestURI()+"?page="+(currentPage+1) );





        //制定视图,也就是list.jsp

        ModelAndView mav=new ModelAndView("list");

        mav.addObject("articles",articles);

        mav.addObject("pageStr",pageStr);

        return mav;

    }

然后运行程序,进入分页页面,你就可以看到结果了:

Mybatis学习(7)实现mybatis分页的更多相关文章

  1. MyBatis学习总结(七)——Mybatis缓存(转载)

      孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(七)--Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的 ...

  2. 【转】MyBatis学习总结(七)——Mybatis缓存

    [转]MyBatis学习总结(七)——Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualC ...

  3. 【转】MyBatis学习总结(一)——MyBatis快速入门

    [转]MyBatis学习总结(一)——MyBatis快速入门 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC ...

  4. 转:MyBatis学习总结(Mybatis总结精华文章)

    http://www.cnblogs.com/xdp-gacl/tag/MyBatis%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/ 当前标签: MyBatis学习总结   ...

  5. MyBatis 学习记录5 MyBatis的二级缓存

    主题 之前学习了一下MyBatis的一级缓存,主要涉及到BaseExecutor这个类. 现在准备学习记录下MyBatis二级缓存. 配置二级缓存与初始化发生的事情 首先二级缓存默认是不开启的,需要自 ...

  6. Mybatis学习笔记(一) —— mybatis介绍

    一.Mybatis介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...

  7. Mybatis学习第一天——Mybatis的安装配置以及基本CURD操作

    1.Mybatis下载 Mybatis是开源的持久层框架,能够度jdbc进行简单的封装,但其并不是完全的ORM(Object Relational Mapping,对象关系映射),无法脱离数据库进行适 ...

  8. Mybatis学习笔记(八) —— Mybatis整合spring

    一.整合思路 1.SqlSessionFactory对象应该放到spring容器中作为单例存在. 2.传统dao的开发方式中,应该从spring容器中获得sqlsession对象. 3.Mapper代 ...

  9. MyBatis学习笔记一:MyBatis最简单的环境搭建

    MyBatis的最简单环境的搭建,使用xml配置,用来理解后面的复杂配置做基础 1.环境目录树(导入mybatis-3.4.1.jar包即可,这里是为后面的环境最准备使用了web项目,如果只是做 my ...

  10. MyBatis学习总结_12_Mybatis+Mysql分页查询

    package cn.tsjinrong.fastfile.util; /** * @ClassName: Page * @Description: TODO(分页组件的父类,用来封装分页的 通用内容 ...

随机推荐

  1. CCproxy 代理上网

    相信有些同学在工作过程中遇到过公司内网环境无法上网的情况,下面给大家介绍一下CCproxy代理上网的配置 场景:linux虚拟机通过CCproxy代理访问外网 环境:只能访问内网的linux环境,可以 ...

  2. 提高IO输出速度

    用DMA内存到内存的模式,直接把Gpio_data的数据循环的搬到GPIOC的BSRR寄存器上来控制GPIOC上电平的翻转,这样使得GPIO的速度达到了最快,输出70ns的脉宽,这已经是达到了DMA总 ...

  3. Java反射机制详情

    1.运行环境 JDK8+lntellij IDEA 2018.3 2.反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个 ...

  4. sklearn中,数据集划分函数 StratifiedShuffleSplit.split() 使用踩坑

    在SKLearn中,StratifiedShuffleSplit 类实现了对数据集进行洗牌.分割的功能.但在今晚的实际使用中,发现该类及其方法split()仅能够对二分类样本有效. 一个简单的例子如下 ...

  5. 在js中将map对象转换成json 和 js对cookie的操作

    在js中将map对象转换成json //msp转objectlet obj= Object.create(null); for (let[k,v] of map) { obj[k] = v; }//o ...

  6. typeof的作用及用法

    typeof的作用及用法 1.检查一个变量是否存在,是否有值. typeof在两种情况下会返回"undefined":一个变量没有被声明的时候,和一个变量的值是undefined的 ...

  7. 视频动作定位的分层自关注网络:ICCV2019论文解析

    视频动作定位的分层自关注网络:ICCV2019论文解析 Hierarchical Self-Attention Network for Action Localization in Videos 论文 ...

  8. TensorFlow反向传播算法实现

    TensorFlow反向传播算法实现 反向传播(BPN)算法是神经网络中研究最多.使用最多的算法之一,用于将输出层中的误差传播到隐藏层的神经元,然后用于更新权重. 学习 BPN 算法可以分成以下两个过 ...

  9. Yolov4性能分析(上)

    Yolov4性能分析(上) 一.目录 实验测试 1) 测试介绍 2) Test 3) Train 二.   分析 1.实验测试 1. 1  实验测试方法 Yolov4训练train实验方法(Darkn ...

  10. PyTorch中的MIT ADE20K数据集的语义分割

    PyTorch中的MIT ADE20K数据集的语义分割 代码地址:https://github.com/CSAILVision/semantic-segmentation-pytorch Semant ...