一、PageHelper介绍
- PageHelper是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,例如mysql、
oracle、mariaDB、DB2、SQLite、Hsqldb等。 - PageHelper在 github 的项目地址:https://github.com/pagehelper/Mybatis-PageHelper
- PageHelper在 gitosc 的项目地址:http://git.oschina.net/free/Mybatis_PageHelper
二、PageHelper使用
2.1 集成(推荐Maven)
- 在父工程的pom.xml文件中添加依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version><!--最新版本即可-->
</dependency>
2.2 配置
2.2.1 在MyBatis配置文件SqlMapConfig.xml进行配置
- 单独使用MyBatis时,在
SqlMapConfig.xml
中进行配置
<!--
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
2.2.2 在Spring配置文件applicationContext.xml进行配置
applicationContext.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注意其他配置 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
params=value1
</value>
</property>
</bean>
</array>
</property>
</bean>
- 完整配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启注解扫描,管理dao和service-->
<context:component-scan base-package="com.ruki.eams.service" />
<context:component-scan base-package="com.ruki.eams.dao" />
<!--读取数据库配置文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--SqlSessionFactory交给 IOC管理-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--PageHelper插件的传入,后续补充(1018)-->
<!-- 传入PageHelper的插件 -->
<property name="plugins">
<array>
<!-- 传入插件的对象 -->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!--数据库方言-->
<prop key="helperDialect">mysql</prop>
<!--分页合理化,如在第一页,点击上一页还是第一页-->
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>
<!-- 扫描dao接口 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ruki.eams.dao"/>
</bean>
<!--配置Spring声明式事务管理-->
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启对事务的注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
2.3 分页插件参数详解
helperDialect
:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置
helperDialect
属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
oracle , mysql , mariadb , sqlite , hsqldb , postgresql , db2 , sqlserver , informix , h2 , sqlserver2012 ,derby
特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012 ,否则会使用 SqlServer2005 的
方式进行分页。你也可以实现 AbstractHelperDialect
,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
offsetAsPageNum
:默认值为false
,该参数对使用RowBounds
作为分页参数时有效。 当该参数设置为
true
时,会将RowBounds
中的offset
参数当成pageNum
使用,可以用页码和页面大小两个参数进行分页。rowBoundsWithCount
:默认值为false
,该参数对使用RowBounds
作为分页参数时有效。 当该参数设置
为true
时,使用RowBounds
分页会进行count
查询。pageSizeZero
:默认值为false
,当该参数设置为true
时,如果pageSize=0
或者RowBounds.limit =0
就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是Page
类型)。reasonable
:分页合理化参数,默认值为false
。当该参数设置为true
时,pageNum<=0
时会查询第一页,pageNum>pages
(超过总数时),会查询最后一页。默认false
时,直接根据参数进行查询。params
:为了支持startPage(Object params)
方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置pageNum
,pageSize
,count
,pageSizeZero
,reasonable ,不配置映射的用默认值, 默认值为
pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
。supportMethodsArguments
:支持通过Mapper
接口参数来传递分页参数,默认值false
,分页插件会从查询方法的参数值中,自动根据上面params
配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的com.github.pagehelper.test.basic
包下的ArgumentsMapTest
和ArgumentsObjTest
。autoRuntimeDialect
:默认值为false
。设置为true
时,允许在运行时根据多数据源自动识别对应方言
的分页 (不支持自动选择sqlserver2012 ,只能使用sqlserver ),用法和注意事项参考下面的场景五。closeConn
:默认值为true
。当使用运行时动态数据源或没有设置helperDialect
属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true
关闭,设置为
false
后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。
2.4 基本使用
- PageHelper的基本使用有6种,最常用的有两种
2.4.1 RowBounds方式的调用(了解)
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));
- 使用这种调用方式时,你可以使用RowBounds参数进行分页,这种方式侵入性最小,我们可以看到,通过
RowBounds方式调用只是使用了这个参数,并没有增加其他任何内容。 - 分页插件检测到使用了
RowBounds
参数时,就会对该查询进行物理分页。 - 关于这种方式的调用,有两个特殊的参数是针对
RowBounds
的,可以参看上面的分页插件参数介绍 - 注:不只有命名空间方式可以用
RowBounds
,使用接口的时候也可以增加RowBounds
参数,例如:
//这种情况下也会进行物理分页查询
List<Country> selectAll(RowBounds rowBounds);
- 注意: 由于默认情况下的
RowBounds
无法获取查询总数,分页插件提供了一个继承自RowBounds
的
PageRowBounds
,这个对象中增加了total
属性,执行分页查询后,可以从该属性得到查询总数。
2.4.3 PageHelper.startPage 静态方法调用(重点)
- 需要进行分页的 MyBatis 查询方法前调用PageHelper.startPage 静态方法即可,紧
跟在这个方法后的第一个MyBatis 查询方法会被进行分页。
//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);
- 在业务层面中则是在
dao.findAll()
前加入静态方法,需要传入两个参数。
@Override
public List<Product> findAll(int page, int size) throws Exception {
PageHelper.startPage(page, size);
return productDao.findAll();
}
三、订单分页查询案例
3.1 controller
OrdersController
package com.ruki.eams.controller;
import com.github.pagehelper.PageInfo;
import com.ruki.eams.domain.Orders;
import com.ruki.eams.service.IOrdersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
@RequestMapping("/orders")
public class OrdersController {
@Autowired
private IOrdersService ordersService;
/**
* 未分页的查询全部订单
* @return
* @throws Exception
*/
/*@RequestMapping("/findAll.do")
public ModelAndView findAll() throws Exception {
ModelAndView mv = new ModelAndView();
List<Orders> orders = ordersService.findAll();
mv.addObject("ordersList", orders);
mv.setViewName("orders-list");
return mv;
}*/
/**
* 有分页的查询全部订单
* @param page
* @param size
* @return
* @throws Exception
*/
@RequestMapping("/findAll.do")
@Secured("ROLE_ADMIN")// @Secured注解下,前缀不能省略
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") Integer page, @RequestParam(name = "size", required = true, defaultValue = "4") Integer size) throws Exception {
ModelAndView mv = new ModelAndView();
List<Orders> ordersList = ordersService.findAll(page, size);
//PageInfo就是一个分页Bean
PageInfo pageInfo = new PageInfo(ordersList);
mv.addObject("pageInfo", pageInfo);
mv.setViewName("orders-page-list");
return mv;
}
}
3.2 service
IOrdersService
package com.ruki.eams.service;
import com.ruki.eams.domain.Orders;
import java.util.List;
public interface IOrdersService {
List<Orders> findAll(int page, int size) throws Exception;
Orders findById(String orderId) throws Exception;
}
OrdersServiceImpl
package com.ruki.eams.service.impl;
import com.github.pagehelper.PageHelper;
import com.ruki.eams.dao.IOrdersDao;
import com.ruki.eams.domain.Orders;
import com.ruki.eams.service.IOrdersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class OrdersServiceImpl implements IOrdersService {
@Autowired
private IOrdersDao ordersDao;
@Override
public List<Orders> findAll(int page, int size) throws Exception {
//System.out.println("page: "+page+"---"+"size: "+size);
//pageNum是页码值,pageSize是每页显示条数
PageHelper.startPage(page,size);
return ordersDao.findAll();
}
@Override
public Orders findById(String orderId) throws Exception {
return ordersDao.findById(orderId);
}
}
3.3 dao
IOrdersDao
package com.ruki.eams.dao;
import com.ruki.eams.domain.Member;
import com.ruki.eams.domain.Orders;
import com.ruki.eams.domain.Product;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface IOrdersDao {
@Select("select * from orders")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "orderNum", column = "orderNum"),
@Result(property = "orderTime", column = "orderTime"),
@Result(property = "peopleCount", column = "peopleCount"),
@Result(property = "payType", column = "payType"),
@Result(property = "orderDesc", column = "orderDesc"),
@Result(property = "orderStatus", column = "orderStatus"),
@Result(property = "product", column = "productId", javaType = Product.class, one = @One(select = "com.ruki.eams.dao.IProductDao.findById"))
})
List<Orders> findAll() throws Exception;
}
3.4 前端页面
orders-page-list.jsp
<!-- .box-footer-->
<div class="box-footer">
<div class="pull-left">
<div class="form-group form-inline">
总共 ${pageInfo.pages}页,共${pageInfo.total}条数据。 每页
<select class="form-control" id="changePageSize" onchange="changePageSize()">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select> 条
</div>
</div>
<div class="box-tools pull-right">
<ul class="pagination">
<li>
<a href="${pageContext.request.contextPath}/orders/findAll.do?page=1&size=${pageInfo.pageSize}" aria-label="Previous">首页</a>
</li>
<li><a href="${pageContext.request.contextPath}/orders/findAll.do?page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}">上一页</a>
</li>
<c:forEach begin="1" end="${pageInfo.pages}" var="pageNum">
<li><a href="${pageContext.request.contextPath}/orders/findAll.do?page=${pageNum}&size=${pageInfo.pageSize}">${pageNum}</a>
</li>
</c:forEach>
<li><a href="${pageContext.request.contextPath}/orders/findAll.do?page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}">下一页</a></li>
<li><a href="${pageContext.request.contextPath}/orders/findAll.do?page=${pageInfo.pages}&size=${pageInfo.pageSize}" aria-label="Next">尾页</a>
</li>
</ul>
</div>
</div>
<!-- /.box-footer-->
四、总结
在SSM框架下
- 在
pom.xml
中导入jar包依赖。(2.1) - 在
applicationContext.xml
中,对PageHelper进行配置。(2.2.2) - 在真正调用查询方法前,加入静态方法
PageHelper.startPage(page, size);
。(2.4.3) - 前端页面中,进行设置.(3.4)
- 在