SpringMVC+Spring+MyBatis 的综合练习 11 (使用 MyBatis 分页插件 PageHelper)

11.1 准备工作

分页是查询功能中最常用的,基本上是项目必须的。在学习 SpringMVC+Spring+SpringData/JPA 的时候曾经接触了 SpringData中的接口类 PagingAndSortingRepository 。也是用于分页的,因为没有系统学习 SpringData 和 JPA,对该接口的理解不是很透彻(虽然老师在视频中非常详细的分析了源码,说来还是我笨吧)。后期在练习的过程中也总是出现自己无法判断原因的错误。这次因为不是采用的 SpringData/JPA 技术,所以分页选择了 Mybatis 的插件 pageHelper。这个插件看起来相对简单些,而且个人感觉封装的信息非常完整,也很方便调用,非常利于前台搭建。

官网的几个链接

11.2 POM 文件

增加下面的依赖到 pom.xml 文件。

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.2</version>
</dependency>

11.3 配置拦截器插件

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

11.3.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>

11.3.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>
            params=value1
          </value>
        </property>
      </bean>
    </array>
  </property>
</bean>

这两种方法随便用一个就可以,我用的第一种。

11.4 使用 PageHelper 的方法

在 PageHelper 官网的文档中对其使用方法有一大段的说明,调用的方式也是多种多样,视频中老师使用的方法是下面这种,在粗略看过其他方法后,考虑到我的能力和学习成本,决定先研究这种方法,毕竟官网的推荐方法之一应该更靠谱。

PageHelper.startPage 静态方法调用

除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。
在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。

例一:

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
//分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>
assertEquals(182, ((Page) list).getTotal());

例二:

//request: url?pageNum=1&pageSize=10
//支持 ServletRequest,Map,POJO 对象,需要配合 params 参数
PageHelper.startPage(request);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);

//后面的不会被分页,除非再次调用PageHelper.startPage
List<Country> list2 = countryMapper.selectIf(null);
//list1
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
//分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>,
//或者使用PageInfo类(下面的例子有介绍)
assertEquals(182, ((Page) list).getTotal());
//list2
assertEquals(1, list2.get(0).getId());
assertEquals(182, list2.size());

例三,使用PageInfo的用法:

这种方法更适合向前台传送分页数据。

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectAll();
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());

重要提示(还是写在这里吧,省的去官网查了)

  • PageHelper.startPage 方法:
    只有紧跟在PageHelper.startPage方法后的第一个Mybatis的查询(Select)方法会被分页。
  • 请不要配置多个分页插件
    请不要在系统中配置多个分页插件(使用Spring时,mybatis-config.xml和Spring< bean >配置方式,请选择其中一种,不要同时配置多个分页插件)!
  • 分页插件不支持带有for update语句的分页
    对于带有for update的sql,会抛出运行时异常,对于这样的sql建议手动分页,毕竟这样的sql需要重视。
  • 分页插件不支持嵌套结果映射
    由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。

11.5 测试插件

使用如下测试代码测试插件效果。限于篇幅,其中涉及的 Controller 和 Service 部分留到下一篇介绍。实际上,这两部分应该和本篇内容一道完成,否则无法完成测试。

package com.hh.ssm.test;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.github.pagehelper.PageInfo;
import com.hh.ssm.bean.Employee;

/**
 * 使用SpringMVC提供的测试
 * 
 * @author HH
 * 
 */

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:applicationContext.xml",
        "file:src/main/webapp/WEB-INF/dispatcherServlet-servlet.xml" })
public class MvcTest {

    MockMvc mockMvc;
    @Autowired
    WebApplicationContext context;

    @Before
    public void initMockmvc() {
         mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testGetAllEmployeeWithDept() throws Exception {

        String pageNum = "5";
        // 模拟发出 /employees 的 get 请求,传递参数pageNum,返回结果
        MvcResult result = mockMvc.perform(
                    MockMvcRequestBuilders.get("/employees").param("pageNum", pageNum))
                    .andReturn();
        // 把结果封装到 request 域
        MockHttpServletRequest request = result.getRequest();
        // 封装 PageInfo 对象
        PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
        // 使用 PageInfo 对象的各种方法得到分页数据
        System.out.println("Total :" + pageInfo.getTotal());
        System.out.println("PageNum :" + pageInfo.getPageNum());
        System.err.println("Pages :" + pageInfo.getPages());
        System.out.println("PageSize :" + pageInfo.getPageSize());
        System.out.println("getStartRow :" + pageInfo.getStartRow());
        System.out.println("getEndRow :" + pageInfo.getEndRow());

        List<Employee> employees =  pageInfo.getList();
        for (Employee employee : employees) {
            System.out.println(employee);
        }

        ArrayList<Integer> navigatePageList = new ArrayList<Integer>();

        int[] navigatePageNums = pageInfo.getNavigatepageNums();
        System.out.println("navagatePageNums : "+ navigatePageNums);
        for (int i = 0; i < navigatePageNums.length; i++) {
            navigatePageList.add(navigatePageNums[i]);
        }
        System.out.println("navigatePageList: "+navigatePageList.toString());       
    }
}

运行结果如下:
运行结果

扫描二维码关注公众号,回复: 1891413 查看本文章

可以看出分页成功了!!!现在是该考虑前台页面的时候了。

猜你喜欢

转载自blog.csdn.net/hh680821/article/details/79189912