上一篇文章里已经讲到了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. lvresize 调整LVM逻辑卷的空间大小,可以增大空间和缩小空间

    lvresize 相关命令:lvreduce,lvextend,lvdisplay,lvcreate,lvremove,lvscan   lvresize指令:调整逻辑卷空间大小[语    法]lvr ...

  2. spring MyBatis的相关面试题

    (相关面试题! 供参考!) 1.ORM框架有哪些? MyBatis:半自动化框架(不是纯ORM) 需要写动态SQL语句,实体类和SQL语句之间建立映射关系 Spring:轻量级框架, Java EE的 ...

  3. flink Checkpoint优化

    一.设置最小时间间隔 当flink应用开启Checkpoint功能,并配置Checkpoint时间间隔,应用中就会根据指定的时间间隔周期性地对应用进行Checkpoint操作.默认情况下Checkpo ...

  4. 新晋总监生存指南三——OKR

    一.什么是OKR 书接上文:新晋总监生存指南二--建立指标 OKR在我们团队正循环大图中占有很重的分量,好的OKR实践同时也是上文中数据指标实践的案例.反向论述可以认为,数据指标建设混乱的团队很难运用 ...

  5. 微信小程序使用同声传译实现语音识别功能

    我使用同声传译语音识别功能是为了实现微信小程序首页的语音搜索功能,如果你也是那么恭喜你,你可以ctrl+c.ctrl+v再改一改,如果你不是那么你也不要着急的走可以看完我的文章会对你有所帮助! 首先是 ...

  6. JS 反射机制及 Reflect 详解

    一.什么是反射机制 反射机制是在编译阶段不知道是哪个类被加载,而是在运行的时候才加载.执行. 也就是说,反射机制指的是程序在运行时能够获取自身的信息. js 中的 apply 就是反射机制. 二.Re ...

  7. 使用指定源安装python包

    对于经常需要按照那个python包的同学,外网下载比较慢的话,可以使用公司内部的镜像进行安装 eg: pip install django -i http://mirrors.***.com.cn/p ...

  8. DM8_Linux详细安装步骤

    (从虚拟机配置讲起,有基础的可以直接看二,谢谢) 一.虚拟机的安装和配置 软件:virtualbox 系统:centos7 工具:Xshell 官网下载centos7,使用virtualbox安装ce ...

  9. openresty 学习笔记二:获取请求数据

    openresty 学习笔记二:获取请求数据 openresty 获取POST或者GET的请求参数.这个是要用openresty 做接口必须要做的事情.这里分几种类型:GET,POST(urlenco ...

  10. Python+Selenium自动化 模拟鼠标操作

    Python+Selenium自动化 模拟鼠标操作   在webdriver中,鼠标的一些操作如:双击.右击.悬停.拖动等都被封装在ActionChains类中,我们只用在需要使用的时候,导入这个类就 ...