前言
在網站裏我們常常會看到可以分頁的列表,這次我們就通過 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 , 希望對小夥伴們有幫助哦。