上一篇文章里已经讲到了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. JQuery Ajax 请求参数 List 集合处理

    引言 JQuery Ajax 发送请求参数一般都是基本类型,比如 String.int:那么,请求参数如果是 List 集合应该如何处理呢? 情况一:Aajx 发送 List 类型请求参数 举例如下: ...

  2. Lua中的元表(metatable)、元方法(metamethod)详解

    在第一次看见这两样东西的时候,可能会觉得它很深奥,但其实很好理解,虽然实际上它可能真的很深奥.(小若:停!滚粗.) 1.知道为什么1 + 1 = 2吗? 为什么在Lua中,1+1会等于2呢?(小若:难 ...

  3. SystemVerilog MCDF验证结构

    MCDF的设计和验证花费的时间:(工作中假设的时间) design  cycle time  ==10days how about 验证?verify? 模块越往上(大')验证花费的时间越来越大,但是 ...

  4. Linux 安装配置 tftp 服务器

    1.安装TFTP服务 安装服务端 sudo apt-get install tftpd-hpa 安装客服端 sudo apt-get install tftp-hpa 2.创建TFTP服务器目录 cd ...

  5. GO学习-(38) Go语言结构体转map[string]interface{}的若干方法

    结构体转map[string]interface{}的若干方法 本文介绍了Go语言中将结构体转成map[string]interface{}时你需要了解的"坑",也有你需要知道的若 ...

  6. Go语言的GOPATH详解

    在GOLAND中设置GOPATH: 设置好路径后,并不是直接在这个路径下面写代码文件就行了 GO会识别GOPATH下的src目录,而真正的引用的包名,是src下的目录名,然后才是代码模块名 目录结构如 ...

  7. (续篇)Selenium 安装配置以及如何解决('chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/ch)或者(unknown error:cannot find Chrome binary)问题?

    注:本帖针对小小白哦~~(づ ̄3 ̄)づ╭- 接pip安装的帖子,不需要的直接跳过... 首先上图,出现如下的错误,那你可是找到知己了: 或者: 抱歉抱歉,这图截的不太清晰,凑合着用吧,但是也能看出来错 ...

  8. 调试动态加载的js

    用浏览器无法调试异步加载页面里包含的js文件.简单的说就是在调试工具里面看不到异步加载页面里包含的js文件   最近在一个新的web项目中开发功能.这个项目的管理界面有一个特点,框架是固定的,不会刷新 ...

  9. CVPR2020论文解析:实例分割算法

    CVPR2020论文解析:实例分割算法 BlendMask: Top-Down Meets Bottom-Up for Instance Segmentation 论文链接:https://arxiv ...

  10. 使用CUDA Warp-Level级原语

    使用CUDA Warp-Level级原语 NVIDIA GPU以SIMT(单指令,多线程)的方式执行称为warps 的线程组.许多CUDA程序通过利用warp执行来实现高性能.本文将展示如何使用cud ...