Spring Boot2 实战系列之使用分页插件PageHelper

前言

在网站里我们常常会看到可以分页的列表,这次我们就通过 springboot + thymeleaf + pagehelper 来实现这一功能。PageHelper 是开源的 MyBatis 分页插件, 支持任何复杂的单表、多表分页,详细使用方法可查看 官方文档

下面通过一个展示商品信息的页面来演示怎样使用 pagehelper

创建项目

项目结构图如下:
在这里插入图片描述

pom 依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>top.yekongle</groupId>
	<artifactId>springboot-pagehelper-sample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot-pagehelper-sample</name>
	<description>Pagehelper sample for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

代码编写

首先先创建一个名为 product 的数据表,并插入一些数据

# Host: localhost  (Version 5.7.21-log)
# Date: 2020-04-24 00:00:40
# Generator: MySQL-Front 6.0  (Build 2.20)


#
# Structure for table "product"
#

DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `category` varchar(10) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `discount` varchar(10) DEFAULT NULL,
  `price` double(10,0) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#
# Data for table "product"
#

INSERT INTO `product` VALUES (1,'零食','卫龙辣条','8折',10),(2,'洗发水','霸王','8折',69),(3,'手机','小米10','',3499),(4,'手机','小米10 Pro','',4999),(5,'手机','华为P40','',4499),(6,'男装','T恤','',59),(7,'男装','休闲裤','',89),(8,'男装','牛仔裤','',99),(9,'数码','游戏主机','',5999),(10,'数码','数码相机','',5999),(11,'办公','打印机','',2999),(12,'办公','投影机','',1999),(13,'办公','会议白板','',999);

Product.java,商品实体类

package top.yekongle.pagehelper.entity;

import lombok.Data;

/** 
* @Description: 
* @Author: Yekongle 
* @Date: 2020年4月22日
*/
@Data
public class Product {
	private Integer id;
	private String category;
	private String name;
	private String discount;
	private double price;
}

ProductMapper.java,商品数据操作接口

package top.yekongle.pagehelper.mapper;

import java.util.List;

import top.yekongle.pagehelper.entity.Product;

/** 
* @Description: 
* @Author: Yekongle 
* @Date: 2020年4月22日
*/
public interface ProductMapper {
	List<Product> listProduct();
}

在 resources 下新建一个 mybatis 目录,创建 mybatis 配置文件

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>

</configuration>

在 mybatis 目录下新建一个 mapper 目录存放 mapper.xml 文件
ProductMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="top.yekongle.pagehelper.mapper.ProductMapper">

	<select id="listProduct" resultType="Product">
		SELECT * from product order by id
	</select>

</mapper>

编辑全局配置文件,配置数据库连接信息,thymeleaf 配置,mybatis 配置以及 pagehelper 配置。
application.properties

# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytest?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC  
spring.datasource.username=root
spring.datasource.password=yekongle

# Thymeleaf 配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false

# mybatis 配置
mybatis.type-aliases-package=top.yekongle.pagehelper.entity
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

# pagehelper 配置
# 指定分页插件使用哪种方言
pagehelper.helper-dialect=mysql
# 在分页查询时进行 count 查询
pagehelper.row-bounds-with-count=true
# 用户输入的页数不在合法范围能够正确的响应到正确的结果页面, pageNum<=0 会查询第一页, pageNum>总页数 会查询最后一页
pagehelper.reasonable=true

PageController.java,页面控制类,在这里使用 pagehelper 获取想要的页面和记录数并返回到前端

package top.yekongle.pagehelper.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import lombok.extern.slf4j.Slf4j;
import top.yekongle.pagehelper.entity.Product;
import top.yekongle.pagehelper.mapper.ProductMapper;

/** 
* @Description: 页面控制类
* @Author: Yekongle 
* @Date: 2020年4月22日
*/

@Slf4j
@Controller
public class PageController {
	
	@Autowired
	private ProductMapper productMapper;

	/**
	 * async: 是否已加载
	 * pageNum:当前页
	 * pageSize:每页的数量
	 * */	
	@GetMapping
	public ModelAndView index(@RequestParam(value = "async", required = false) boolean async,
			@RequestParam(value = "pageNum", required = false, defaultValue = "0") int pageNum, 
			@RequestParam(value = "pageSize", required = false, defaultValue = "1") int pageSize, Model model) {
		log.info("pageNum{}, pageSize{}", pageNum, pageSize);
		// 开始分页
		PageHelper.startPage(pageNum, pageSize);
		List<Product> productList = productMapper.listProduct();
		
		PageInfo page = new PageInfo(productList);
		model.addAttribute("page", page);
		
		return new ModelAndView(async == true ? "index :: #mainContainerRepleace" : "index", "userModel",
				model);
	}
}

SpringbootPagehelperSampleApplication.java, 启动类, @MapperScan: 指定mapper所在包

package top.yekongle.pagehelper;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 项目启动类
 * @MapperScan:指定mapper所在包
 * */
@SpringBootApplication
@MapperScan("top.yekongle.pagehelper.mapper")
public class SpringbootPagehelperSampleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootPagehelperSampleApplication.class, args);
	}

}

前端页面编写,分为头部(header),尾部(footer),页码控制(page) 和 主页(index)

header.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" data-th-fragment="header">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link href="../../css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
   <!-- toastr CSS -->
    <link href="../../css/toastr.min.css" th:href="@{/css/toastr.min.css}" rel="stylesheet">
	<!-- Font-Awesome CSS -->
    <link href="../../css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet">
</head>
<body>
</body>
</html>

footer.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
	<footer class="blog-footer bg-inverse" data-th-fragment="footer">
		<div class="container">
			<p class="m-0 text-center text-white">
				© 2020 <a href="https://www.yekongle.top">yekongle.top</a>
			</p>
		</div>

		<!-- JavaScript -->
		<script src="../js/jquery.min.js" th:src="@{/js/jquery.min.js}"></script>
		<script src="../js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
		<script src="../js/main.js" th:src="@{/js/main.js}"></script>
		<script src="../js/thymeleaf-bootstrap-paginator.js" th:src="@{/js/thymeleaf-bootstrap-paginator.js}"></script>
		<script src="../js/toastr.min.js" th:src="@{/js/toastr.min.js}"></script>
	</footer>

</body>
</html>

page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>

<nav data-th-fragment="page" data-th-if="${page.total gt 0}" data-th-object="${page}">

    <!-- 处理页数小于等于7 的情况 -->
    <ul class="pagination" data-th-if="${page.pages le 7}">
        <!-- 总记录数 -->
        <li class="tbpage-total-elements disabled">共[[${page.total}]]条</li>

        <!-- 页面大小 -->
        <select class="custom-select tbpage-size" data-th-attr="pageSize=${page.pageSize}">
            <option data-th-each="i : ${#arrays.toIntegerArray({1, 3, 5,10,40,100})}" data-th-value="${i}"
                    data-th-selected="${i eq page.pageSize}" data-th-text="${i}"></option>
        </select>


        <!-- 上一页 -->
        <li class="page-item" data-th-classappend="${page.isFirstPage} ? 'disabled' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.prePage}"
               aria-label="Previous">
                <span aria-hidden="true">«</span>
            </a>
        </li>

        <!-- 迭代生成页码 -->
        <li class="page-item" data-th-each="i : ${#numbers.sequence(1, page.pages)}"
            data-th-classappend="${page.pageNum eq i} ? 'active' : ''">
            <a class="page-link tbpage-item" data-th-attr="pageNum=${i}" href="javascript:void(0);">
                <span data-th-text="${i}"></span>
            </a>
        </li>


        <!-- 下一页 -->
        <li class="page-item" data-th-classappend="${page.isLastPage} ? 'disabled' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.nextPage}"
               aria-label="Next">
                <span aria-hidden="true">»</span>
            </a>
        </li>
    </ul>


    <!-- 处理页数大于7 的情况 -->
    <ul class="pagination" data-th-if="${page.pages gt 7}">
        <!-- 总记录数 -->
        <li class="tbpage-total-elements disabled">共[[${page.total}]]条</li>

        <!-- 页面大小 -->
        <select class="custom-select tbpage-size" data-th-attr="pageSize=${page.pageSize}">
            <option data-th-each="i : ${#arrays.toIntegerArray({1, 5,10,40,100})}" data-th-value="${i}"
                    data-th-selected="${i eq page.pageSize}" data-th-text="${i}"></option>
        </select>

        <!-- 上一页 -->
        <li class="page-item" data-th-classappend="${page.isFirstPage} ? 'disabled' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.prePage}"
               aria-label="Previous">
                <span aria-hidden="true">«</span>
            </a>
        </li>

        <!-- 首页 -->
        <li class="page-item" data-th-classappend="${page.pageNum eq 1} ? 'active' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=0">1</a>
        </li>


        <!-- 当前页面小于等于4 -->
        <li class="page-item" data-th-if="${page.pageNum le 4}" data-th-each="i : ${#numbers.sequence(2,5)}"
            data-th-classappend="${page.pageNum eq i} ? 'active' : ''">
            <a class="page-link tbpage-item" href="javascript:void(0);" data-th-attr="pageNum=${i}">
                <span data-th-text="${i}"></span>
            </a>
        </li>

        <li class="page-item disabled" data-th-if="${page.pageNum le 4}">
            <a href="javascript:void(0);" class="page-link tbpage-item">
                <span aria-hidden="true">...</span>
            </a>
        </li>

        <!-- 最后一页与当前页面之差,小于等于3 -->
        <li class="page-item disabled" data-th-if="${(page.pages-page.pageNum) le 3}">
            <a href="javascript:void(0);" class="page-link tbpage-item">
                <span aria-hidden="true">...</span>
            </a>
        </li>
        <li class="page-item" data-th-if="${(page.pages-page.pageNum) le 3}"
            data-th-each="i : ${#numbers.sequence(page.pages-3, page.pages-1)}"
            data-th-classappend="${page.pageNum eq i} ? 'active' : ''">
            <a class="page-link tbpage-item" href="javascript:void(0);" data-th-attr="pageNum=${i}">
                <span data-th-text="${i}"></span>
            </a>
        </li>

        <!-- 最后一页与当前页面之差大于3,且当前页面大于4-->

        <li class="page-item disabled"
            data-th-if="${(page.pageNum gt 4) && ((page.pages - page.pageNum) gt 3 )}">
            <a href="javascript:void(0);" class="page-link tbpage-item">
                <span aria-hidden="true">...</span>
            </a>
        </li>
        <li class="page-item active" data-th-if="${(page.pageNum gt 4) && ((page.pages-page.pageNum) gt 3 )}">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.pageNum}">[[${page.pageNum}]]</a>
        </li>
        <li class="page-item"
            data-th-if="${(page.pageNum gt 4) && ((page.pages - page.pageNum) gt 3 )}">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.pageNum + 1}">[[${page.pageNum
                + 1}]]</a>
        </li>
        <li class="page-item" data-th-if="${(page.pageNum gt 4) && ((page.pages-page.pageNum) gt 3 )}">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.pageNum} + 2">[[${page.pageNum
                + 2}]]</a>
        </li>

        <li class="page-item disabled"
            data-th-if="${(page.pageNum gt 4) && ((page.pages-page.pageNum) gt 3 )}">
            <a href="javascript:void(0);" class="page-link tbpage-item">
                <span aria-hidden="true">...</span>
            </a>
        </li>

        <!-- 最后一页 -->
        <li class="page-item" data-th-classappend="${page.pageNum eq page.pages} ? 'active' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.pages}">[[${page.pages}]]</a>
        </li>

        <!-- 下一页 -->
        <li class="page-item" data-th-classappend="${page.isLastPage} ? 'disabled' : ''">
            <a href="javascript:void(0);" class="page-link tbpage-item" data-th-attr="pageNum=${page.nextPage}"
               aria-label="Next">
                <span aria-hidden="true">»</span>
            </a>
        </li>
    </ul>

</nav>

</body>
</html>

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/header :: header}">
</head>
<body>
	<div id="mainContainer" class="container">
		<div id="mainContainerRepleace" class="row">
			<table class="table table-striped">
				<thead>
					<tr>
						<th data-field="id">ID</th>
						<th data-field=“category”>类别</th>
						<th data-field="name">名字</th>
						<th data-field="price">价格(元)</th>
						<th data-field="discount">优惠</th>
					</tr>
				</thead>
				<tbody>
					<tr th:each="product : ${page.list}">
						<td th:text="${product.id}">1</td>
						<td th:text="${product.category}">1</td>
						<td th:text="${product.name}">1</td>
						<td th:text="${product.price}">1</td>
						<td th:text="${product.discount}">1</td>
					</tr>
				</tbody>
			</table>
			<div th:replace="~{fragments/page :: page}">...</div>
		</div>
	</div>

	<div th:replace="~{fragments/footer :: footer}">...</div>

</body>
</html>

运行演示

项目启动后,访问 8080 端口

每页展示一条记录
在这里插入图片描述

每页展示一百条记录
在这里插入图片描述
项目已上传至 Github: https://github.com/yekongle/springboot-code-samples/tree/master/springboot-pagehelper-sample , 希望对小伙伴们有帮助哦。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值