分页插件PageHelper的使用

PageHelper的使用

PageHelper是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,例如mysql、oracle、mariaDB、DB2、SQLite、Hsqldb等。

网址:https://pagehelper.github.io/

本项目在 github 的项目地址:https://github.com/pagehelper/Mybatis-PageHelper

本项目在 gitosc 的项目地址:http://git.oschina.net/free/Mybatis_PageHelper

PageHelper配置

1.集成

引入分页插件有下面2种方式,推荐使用 Maven 方式。

1.1. 引入 Jar 包

你可以从下面的地址中下载最新版本的 jar 包

https://oss.sonatype.org/content/repositories/releases/com/github/pagehelper/pagehelper/

http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/

由于使用了sql 解析工具,你还需要下载 jsqlparser.jar:

http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/0.9.5/

1.2. 使用 Maven

在 pom.xml 中添加如下依赖:

<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>最新版本</version>
</dependency>

2.配置

特别注意,新版拦截器是 com.github.pagehelper.PageInterceptorcom.github.pagehelper.PageHelper 现在是一个特殊的 dialect 实现类,是分页插件的默认实现类,提供了和以前相同的用法。

2.1. 在 MyBatis 配置 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. 在 Spring 配置文件中配置拦截器插件

使用 spring 的属性配置方式,可以使用 plugins 属性像下面这样配置:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <!-- 注意其他配置 -->
 <property name="plugins">
   <array>
     <bean class="com.github.pagehelper.PageInterceptor">
       <property name="properties">
         <!--使用下面的方式配置参数,一行配置一个 -->
         <value>
           <prop key="helperDialect">oracle</prop>
     <prop key="reasonable">true</prop>
         </value>
       </property>
     </bean>
   </array>
 </property>
</bean>

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 包下的 ArgumentsMapTestArgumentsObjTest

autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五

closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

4.基本使用

PageHelper的基本使用有6种,大家可以查看文档,最常用的有两种

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 无法获取查询总数,分页插件提供了一个继承自 RowBoundsPageRowBounds,这个对象中增加了 total 属性,执行分页查询后,可以从该属性得到查询总数。

4.2. PageHelper.startPage 静态方法调用(重点)

这种方式是我们要掌握的在你需要进行分页的 MyBatis 查询方法前调用PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);
注:以上摘自PageHelper官方文档

分页效果:

分页.PNG

分页代码编写

<!--分页插件在Spring的配置-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
   <!--配置数据源-->
   <property name="dataSource" ref="dataSource"/>
   <!--配置别名-->
   <property name="typeAliasesPackage" value="fun.chenqi.domain"/>
   <!--配置分页插件-->
   <property name="plugins">
       <array>
           <bean class="com.github.pagehelper.PageInterceptor">
               <property name="properties">
                   <value>
                       <!--helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式 -->
                       <!--reasonable:
                       分页合理化参数,默认值为false。
                       当该参数设置为 true 时,pageNum<=0 时会查询第一页,
                       pageNum>pages(超过总数时),会查询最后一页。
                       默认false 时,直接根据参数进行查询。
                       -->
                       helperDialect=oracle
                       reasonable=true
                   </value>
               </property>
           </bean>
       </array>
   </property>
</bean>
// Controller代码
// 查询所有的路线带分页 使用pageHelper的方式
// RequestParam注解实现参数绑定
// value:请求参数中的名称。
// defaultValue:默认值
// required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@RequestMapping("/findByPageHelper")
public String findByPageHelper(
       @RequestParam(required = true, defaultValue = "1") int pageNum, // pageNum当前页数                     // pageSize每页显示几条数据
       @RequestParam(required = true, defaultValue = "5") int pageSize, Model model) throws Exception {
   // 分页查询
  // PageInfo 里面已经封装好了分页所需要的信息和展示到页面的信息
   PageInfo page = service.findByPageHelper(pageNum, pageSize);
   model.addAttribute("page", page);
   return "product-list";
}
// Service代码
// 查询所有路线带分页
@Override
public PageInfo findByPageHelper(int pageNum, int pageSize) throws Exception {
   // 开始分页 设置第几页 每次查询的条数
   PageHelper.startPage(pageNum, pageSize);
   //紧跟着的第一个select方法会被分页
   List<Product> list = dao.findAll();

   // 创建PageInfo类 封装数据
   PageInfo<Product> page = new PageInfo<>(list);
   return page;
}
// Dao层Sql语句不变
@Select("select * from product")
List<Product> findAll() throws Exception;
<!--JSP页面代码-->
<tbody>
<tr>
   <c:forEach items="${page.list}" var="product">
   <td><input name="ids" type="checkbox"></td>
   <td>${product.productNum}</td>
   <td>${product.productName}</td>
   <td>${product.cityName}</td>
   <td>${product.departureTimeStr}</td>
   <td>${product.productPrice}</td>
   <td>${product.productStatusStr}</td>
   <td>${product.productDesc}</td>
   <td class="text-center">
       <button type="button" class="btn bg-olive btn-xs"               onclick='location.href="${pageContext.request.contextPath}/product/findProductById?id=${product.id}"'>
           修改
       </button>
       <button type="button" class="btn bg-olive btn-xs"
               onclick='javascript:deleteProduct(${product.id})'>删除
       </button>
   </td>
</tr>
</c:forEach>
</tbody>

 <div class="box-footer">
                   <div class="pull-left">
                       <div class="form-group form-inline">
                           总共${page.pages} 页,共${page.total} 条数据。
                           每页
                         <select class="form-control" onchange="submitPageSize(this)" , id="pageSelect">
                           <option value="5"
                                   <c:if test="${page.pageSize==5}">selected</c:if> >5
                           </option>
                           <option value="10"
                           <%--
                           <c:if test="${page.pageSize==10}">selected</c:if>
                           --%>
                           ${page.pageSize==10?"selected":""} >10
                           </option>
                       </select>
                       </div>
                       <script type="text/javascript">
                           function submitPageSize(who) {
                               // 获取数据的方式
                               // document.getElementById("pageSelect").value;
                               // $("#pagepageSelect").val();
                               location.href = "${pageContext.request.contextPath}/product/findByPageHelper?pageSize=" + who.value;
                           }
                       </script>
                   </div>

                   <div class="box-tools pull-right">
                       <ul class="pagination">
                           <li><a href="javascript:submitPageNum(1)" aria-label="Previous">首页</a></li>
                           <li><a href="javascript:submitPageNum(${page.prePage})">上一页</a></li>

                           <c:choose>
                               <c:when test="${page.pages <= 5}">
                                   <c:set var="begin" value="1" />
                                   <c:set var="end" value="${page.pages}" />
                               </c:when>
                               <%--页数超过了5页--%>
                               <c:otherwise>
                                   <c:set var="begin" value="${page.pageNum-2}" />
                                   <c:set var="end" value="${page.pageNum + 2}" />
                                   <%--如果begin减1后为0,设置起始页为1,最大页为5--%>
                                   <c:if test="${begin -1 <= 0}">
                                       <c:set var="begin" value="1" />
                                       <c:set var="end" value="5" />
                                   </c:if>
                                   <%--如果end超过最大页,设置起始页=最大页-4--%>
                                   <c:if test="${end > page.pages}">
                                       <c:set var="begin" value="${page.pages - 4}" />
                                       <c:set var="end" value="${page.pages}" />
                                   </c:if>
                               </c:otherwise>
                           </c:choose>
                         
                          <%-- <c:forEach begin="1" end="${page.pages}" var="i">
                               <li><a href="javascript:submitPageNum(${i})">${i}</a></li>
                           </c:forEach>
                           --%>
                           <c:forEach  begin="${begin}" end="${end}" var="i">
                               <li ><a <c:if test="${page.pageNum==i }">style="color: blue"</c:if>
                                       href="${pageContext.request.contextPath }/product/findByPageHelper?pageNum=${i}&pageSize=${pageInfo.pageSize}">${i }</a></li>
                           </c:forEach>
                           <li><a href="javascript:submitPageNum(${page.nextPage})">下一页</a></li>
                           <li><a href="javascript:submitPageNum(${page.pages})" aria-label="Next">尾页</a></li>
                       </ul>
                   </div>
                   <script type="text/javascript">
                       function submitPageNum(pageNum) {
                           location.href = "${pageContext.request.contextPath}/product/findByPageHelper?pageNum=" + pageNum;
                       }
                   </script>
               </div>          
           </div>

发表评论