上一篇文章里已经讲到了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. component: resolve => require(['../pages/home.vue'], resolve)-装载

    import Vue from 'vue'import VueRouter from 'vue-router'// "@"相当于".."import Detai ...

  2. 10.9 ping:测试主机之间网络的连通性

    ping命令 可用于测试主机之间网络的连通性.执行ping命令会使用ICMP传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而可得知该主机运作正常.     ping命令 ...

  3. 19c PDB数据泵迁入

    1.问题描述 用数据泵进行pdb的迁入迁出,模拟测试将其他库的数据导入到19cpdb中 2.环境介绍 source:12.2.0.1.0 target:19.0.0.0.0 3.源端制造数据 创建表空 ...

  4. JDK8中Stream使用解析

    JDK8中Stream使用解析 现在谈及JDK8的新特新,已经说不上新了.本篇介绍的就是Stream和Lambda,说的Stream可不是JDK中的IO流,这里的Stream指的是处理集合的抽象概念『 ...

  5. NVIDIA Turing Architecture架构设计(下)

    NVIDIA Turing Architecture架构设计(下) GDDR6 内存子系统 随着显示分辨率不断提高,着色器功能和渲染技术变得更加复杂,内存带宽和大小在 GPU 性能中扮演着更大的角色. ...

  6. C++标准模板库(STL)——set常见用法详解

    set的定义 set<typename> name; typename可以是任何基本类型,如int.double.char.结构体等,也可以是STL标准容器,如vector.set.que ...

  7. 八、配置Tomcat日志

    [root@svr5 ~]# vim /usr/local/tomcat/conf/server.xml .. .. <Host name="www.a.com" appBa ...

  8. 基于Android平台的图书管理系统的制作(2)

    上一篇讲解了制作图书管理系统的初衷与要求,和app首页的代码. 下面来介绍图书管理系统的服务对象:学生 学生类的设计: 个人信息:账号.密码.姓名.学号.邮箱.年龄. 借阅信息:借阅总数(不超过十本) ...

  9. 实现一个带有动效的 React 弹窗组件

    我们在写一些 UI 组件时,若不考虑动效,就很容易实现,主要就是有无的切换(类似于 Vue 中的 v-if 属性)或者可见性的切换(类似于 Vue 中的 v-show 属性). 1. 没有动效的弹窗 ...

  10. 魔镜魔镜,今天有雨吗?——GitHub 热点速览 v.21.25

    作者:HelloGitHub-小鱼干 上周智能驾驶项目的作者曾经做过一个透明小电视机,同透明电视机类似 MagicMirror 也是一个神奇的智能项目,使用它进行模块定制开发,你将拥有一块非常酷炫的智 ...