pagerHelper的使用

3 篇文章 0 订阅
1 篇文章 0 订阅
  1. 分页原理
  2. 学习分页插件PageHelper的使用
  3. 使用PageHelper实现产品列表分页查询
	重点:
		分页插件要能在项目中使用,能使用SpringSecurity在项目中实现用户拦截配置

第1章 分页原理

1.1 SQL实现分析
1.1.1 Oracle分页(了解)
1.1.1.1 Oracle中不带排序的分页
select * from
  (
    select rownum rn,p.* from product p
  ) rp 
where 
  rp.rn between 1 and 3;
1.1.1.2 Oracle中带排序的分页
--把rn作为分页的条件
select * from
  (  
     --在排序结果中再次查询,把rownum作为结果集的一列
     select rownum rn,p.* from
       (
           --查询同时实现排序
           select * from product order by productprice desc
        ) p
  ) 
  where 
        rn between 1 and 3;
1.1.2 MySQL分页

MySQL中的分页相对而言比较简单,直接使用limit实现分页即可。

select * from product order by productprice desc limit 0,10
1.1.3 分析

从上面2个分页语句来看,针对不同数据库的分页,都需要2个参数,分别是第几页和每页显示多少条,也就是用户每次进行分页的时候,都应该讲第几页和每页显示多少条数据的2个参数传入到后台。

分页效果如下:

1554155317497

1.2 实现产品列表分页查询
1.2.1 分页工具类的封装

通过上面的图片,我们可以看到,每次都有对应的分页信息需要现实,我们可以讲对应的分页信息封装起来,封装代码如下:

public class PageBean<T> {
	
	// 当前页,手动添加的默认值是1
	private int pageCode = 1;
	
	// 总页数
	// private int totalPage;
	
	// 总记录数
	private int totalCount;
	
	// 每页显示的记录条数,每页显示5条
	private int pageSize = 5;
	
	// 每页显示的数据
	private List<T> beanList;
	
	public int getPageCode() {
		return pageCode;
	}
	public void setPageCode(int pageCode) {
		this.pageCode = pageCode;
	}
	
	/**
	 * 调用getTotalPage() 获取到总页数
	 * JavaBean的属性规定:totalPage是JavaBean是属性 ${pageBean.totalPage}
	 * @return
	 */
	public int getTotalPage() {
		// 计算
		int totalPage = totalCount / pageSize;
		// 说明整除
		if(totalCount % pageSize == 0){
			return totalPage;
		}else{
			return totalPage + 1;
		}
	}
	
	/*public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}*/
	
	public int getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public List<T> getBeanList() {
		return beanList;
	}
	public void setBeanList(List<T> beanList) {
		this.beanList = beanList;
	}
}
1.2.2 Controller代码实现

根据上面的分析,前台需要向后台传递2个参数,分别是每页显示多少条(size)和当前页(page),一般我们在查询列表页的时候,第一次请求不会加分页参数,所以应该要给他们默认参数,首次请求列表页,我们可以让size=5,page=1,这也符合工作中的现实要求。

修改ProductController,将列表查询的方法做如下改造:

/***
 * 商品列表查询
 * @param model
 * @return
 */
@RequestMapping(value = "/list")
public String list(@RequestParam(value = "page",required = false,defaultValue = "1")int page,
                   @RequestParam(value = "size",required = false,defaultValue = "5")int size,
                   Model model){
    //集合查询
    PageBean<Product> pageInfo = productService.pageList(page,size);
    //将数据存入到Model中
    model.addAttribute("pageInfo",pageInfo);
    return "product-list";
}
1.2.3 Service代码实现

修改ProductService接口

//接口
PageBean<Product> pageList(int page, int size);

修改ProductServiceImpl实现类

 /***
 * 产品分页查询
 * @param page
 * @param size
 * @return
 */
@Override
public PageBean<Product> pageList(int page, int size) {
    //创建一个PageBean
    PageBean<Product> pageInfo = new PageBean<Product>();

    //查询总数
    int total = productDao.findCount();
    pageInfo.setTotalCount(total);

    /***
     * 查询列表记录
     */
    List<Product> products = productDao.pageList((page-1)*size,page*size);
    pageInfo.setBeanList(products);
    return pageInfo;
}
1.2.4 Dao代码实现

修改ProductDao,由于我们之前传递的入参是一个JavaBean对象,所以可以直接用#{属性名}来取对应SQL语句占位符的参数,但是如果入参是多个基本数据类型或者多个String类型,我们就无法像之前那么去取,我们可以使用一个注解来实现参数别名的标记@Param(value=“别名”),用@Param之后,SQL语句就可以直接取@Param(value=“name”)中的name了。

/***
 * 分页查询
 * 我们这里采用了不使用排序的分页方式
 * @return
 * @param start
 * @param end
 */
@Select("select * from product limit #{start} , #{end}")
List<Product> pageList(@Param(value = "start")int start, @Param(value = "end")int end);
1.2.5 product-list.jsp改造

将c:forEach中的items所取的迭代对象换成pageInfo.beanList,其他不变。

<tbody>
	<c:forEach items="${pageInfo.beanList}" var="product">
		<tr>
			<td><input name="ids" value="${product.id}" type="checkbox"></td>
			//...略
		</tr>
	</c:forEach>
</tbody>

分页数据填充

<div class="box-footer">
	<div class="pull-left">
		<div class="form-group form-inline">
			总共${pageInfo.totalPage}页,共${pageInfo.totalCount} 条数据。 每页
			<select iclass="form-control">
				<option>5</option>
				<option>10</option>
				<option>15</option>
				<option>20</option>
				<option>50</option>
				<option>80</option>
			</select> 条
		</div>
	</div>

	<div class="box-tools pull-right">
		<ul class="pagination">
			<li><a href="/product/list?page=1" aria-label="Previous">首页</a></li>
			<li><a href="/product/list?page=${pageInfo.pageCode-1}">上一页</a></li>
			<c:forEach begin="1" end="${pageInfo.totalPage}" var="i">
				<li><a href="/product/list?page=${i}">${i}</a></li>
			</c:forEach>
			<li><a href="/product/list?page=${pageInfo.pageCode+1}">下一页</a></li>
			<li><a href="/product/list?page=${pageInfo.totalPage}" aria-label="Next">尾页</a></li>
		</ul>
	</div>
</div>

第2章 分页插件PageHelper

2.1 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
分页插件学习文档:https://pagehelper.github.io/docs/howtouse/
这个案例用到了AdminLTE项目,下面是我的中文-jsp版本
分页插件中文-jsp版本地址:https://github.com/MainPoser/AdminLTE-jsp-chinese
2.2 PageHelper集成到项目中

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

2.2.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/
2.2.2 Maven方式
  <!--分页插件-->
  <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>最新版本</version>
  </dependency>
2.2.4 配置PageHelper

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

2.2.4.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.4.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
               <!--例如、设置数据库方言是mysql-->
              helperDialect=mysql
          </value>
        </property>
      </bean>
    </array>
  </property>
</bean>
2.2.4.3 分页插件参数介绍
  1. helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
    oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby

特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。

  1. offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
  2. rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
  3. pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
  4. reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
  5. params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
  6. supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest。
  7. autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五。
  8. closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。
2.2.4.4 基本使用方法

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

2.2.4.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.2.4.4.2 PageHelper.startPage 静态方法调用*****

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

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf();
2.2.4.4.3 PageInfo介绍

以下是PageHelper自带的分页对象,基本能满足我们平时工作的分页需求,等会我们就直接使用它。

public class PageInfo<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    //当前页
    private int pageNum;
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;

    //由于startRow和endRow不常用,这里说个具体的用法
    //可以在页面中"显示startRow到endRow 共size条数据"

    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总记录数
    private long total;
    //总页数
    private int pages;
    //结果集
    private List<T> list;

    //前一页
    private int prePage;
    //下一页
    private int nextPage;

    //是否为第一页
    private boolean isFirstPage = false;
    //是否为最后一页
    private boolean isLastPage = false;
    //是否有前一页
    private boolean hasPreviousPage = false;
    //是否有下一页
    private boolean hasNextPage = false;
    //导航页码数
    private int navigatePages;
    //所有导航页号
    private int[] navigatepageNums;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;
	//...略
}
2.2.5 集成PageHelper
2.2.5.1 工程中导入PageHelper依赖

使用5.1.2的版本,分别在父工程和dao工程中导入以上包,父工程做版本的管理,子工程直接使用。

修改ssm-parent的pom.xml,在properties中加入版本

<properties>
	//....略

	//分页版本
	<pagehelper.version>5.1.2</pagehelper.version>
</properties>

修改ssm-parent的pom.xml,在dependencies中加入如下依赖

<dependencies>
	//...略

	<!--分页插件-->
	<dependency>
		<groupId>com.github.pagehelper</groupId>
		<artifactId>pagehelper</artifactId>
		<version>${pagehelper.version}</version>
	</dependency>
</dependencies>

修改ssm-dao的pom.xml,在dependencies中加入如下依赖

<dependencies>
	//...略

    <!--分页插件-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
    </dependency>
</dependencies>
2.2.5.2 项目中的配置

在ssm-dao工程中,修改spring-mybatis.xml,找到SqlSessionFactoryBean结点的配置,修改如下:

<!--SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--注入数据源-->
    <property name="dataSource" ref="dataSource" />
    <!--集成分页插件-->
    <property name="plugins">
        <bean class="com.github.pagehelper.PageInterceptor">
            <property name="properties">
                <props>
                    <!--数据库方言选中mysql-->
                    <prop key="helperDialect">mysql</prop>
                    <!--当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页-->
                    <prop key="reasonable">true</prop>
                </props>
            </property>
        </bean>
    </property>
</bean>
2.2.5.3 修改Controller

将返回类型修改成PageInfo,创建一个方法pageHelperList。

/***
 * 商品列表查询
 * @param model
 * @return
 */
@RequestMapping(value = "/list")
public String list(@RequestParam(value = "page",required = false,defaultValue = "1")int page,
                   @RequestParam(value = "size",required = false,defaultValue = "5")int size,
                   Model model){
    //集合查询
    PageInfo<Product> pageInfo = productService.pageHelperList(page,size);
    //将数据存入到Model中
    model.addAttribute("pageInfo",pageInfo);
    return "product-list";
}
2.2.5.4 修改Service
接口:
/***
 * 列表查询
 * @param page
 * @param size
 * @return
 */
PageInfo<Product> pageHelperList(Integer page,Integer size);


实现类:
@Override
public PageInfo<Product> pageHelperList(Integer page, Integer size) {
    //1)静态分页
    PageHelper.startPage(page,size);
    //2)集合查询
    List<Product> products = productMapper.list();
    //3)返回PageInfo:包含数据结果集+分页信息
    return new PageInfo<Product>(products);
}
2.2.5.5 修改Dao
/****
 * 查询
 * @return
 */
@Select("select * from product")
List<Product> list();
2.2.5.6 修改product-list.jsp页面

首先要修改JSP中数据输出

<tbody>
	<c:forEach items="${pageInfo.list}" var="product">
		<tr>
			//...略
		</tr>
	</c:forEach>
</tbody>

找到分页参数,做一定修改,如下:

<div class="box-footer">
	<div class="pull-left">
		<div class="form-group form-inline">
			总共${pageInfo.pages}页,共${pageInfo.total} 条数据。 每页
			<select iclass="form-control" οnchange="submitPageSize(this)">
				<option selected="selected">5</option>
				<option <c:if test="${pageInfo.pageSize==10}">selected="selected"</c:if>>10</option>
			</select> 条
		</div>
	</div>
	<script>
		//每页显示条数变化
		function submitPageSize(option) {
		    /***
			 * 提交查询
             * option.value:获取select的值
             */
			location.href='/product/list?size='+option.value;
        }
	</script>

	<div class="box-tools pull-right">
		<ul class="pagination">
			<li><a href="/product/list?page=1&size=${pageInfo.pageSize}" aria-label="Previous">首页</a></li>
			<li><a href="/product/list?page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}">上一页</a></li>
			<c:forEach begin="1" end="${pageInfo.pages}" var="i">
				<li><a href="/product/list?page=${i}&size=${pageInfo.pageSize}">${i}</a></li>
			</c:forEach>
			<li><a href="/product/list?page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}">下一页</a></li>
			<li><a href="/product/list?page=${pageInfo.pages}&size=${pageInfo.pageSize}" aria-label="Next">尾页</a></li>
		</ul>
	</div>
</div>
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值