在上一个教程中,我们看到了如何在Spring MVC控制器方法中使用参数。以下示例显示了如何将 Spring 数据分页与 Thymeleaf 视图一起使用。我们还将使用注释来更改默认页面大小。Pageable
@PageableDefault
例
实体
package com.example;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.envers.Audited;
@Data
@Entity
@DynamicUpdate
@Audited
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String dept;
private Integer salary;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public static Employee create(String name, String dept, int salary) {
Employee e = new Employee();
e.setName(name);
e.setDept(dept);
e.setSalary(salary);
return e;
}
@Override
public String toString() {
return "Employee{"
+ "id=" + id
+ ", name='" + name + '\''
+ ", dept='" + dept + '\''
+ ", salary=" + salary
+ '}';
}
}
存储 库
package com.example;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
弹簧MVC控制器
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class EmployeeController {
@Autowired
private EmployeeRepository repository;
@GetMapping("/employees")
public String getEmployees(@PageableDefault(size = 10) Pageable pageable,
Model model) {
Page<Employee> page = repository.findAll(pageable);
model.addAttribute("page", page);
return "employee-page";
}
}
百里香叶视图
src/main/webapp/WEB-INF/views/employee-page.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<style>
table{
width:100%;
}
table td, table th {
border: 1px solid grey;
}
table th {
background: #eee;
}
.pagination-div{
user-select: none;
}
.pagination-div span{
border-radius:3px;
border:1px solid #999;
padding:5px;
margin:10px 0px 0px 10px;
display:inline-block
}
span.selected{
background:#ccf;
}
</style>
</head>
<body>
<h2>Employees</h2>
<table>
<tr><th>Id</th>
<th>Name</th>
<th>Department</th>
<th>Salary</th>
</tr>
<tr th:each="employee : ${page.content}">
<td th:text="${employee.id}"></td>
<td th:text="${employee.name}"></td>
<td th:text="${employee.dept}"></td>
<td th:text="${employee.salary}"></td>
</tr>
</table>
<div class="pagination-div">
<span th:if="${page.hasPrevious()}">
<a th:href="@{/employees(page=${page.number-1},size=${page.size})}">Previous</a>
</span>
<th:block th:each="i: ${#numbers.sequence(0, page.totalPages - 1)}">
<span th:if="${page.number == i}" class="selected">[[${i}+1]]</span>
<span th:unless="${page.number == i}">
<a th:href="@{/employees(page=${i},size=${page.size})}">[[${i}+1]]</a>
</span>
</th:block>
<span th:if="${page.hasNext()}">
<a th:href="@{/employees(page=${page.number+1},size=${page.size})}">Next</a>
</span>
</div>
</body>
</html>
运行
要尝试示例,请运行以下示例项目的嵌入式tomcat(在pom中配置.xml):
mvn tomcat7:run-war
输出
本地主机:8080/员工
通过单击页面链接导航到页面:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<link rel="icon" th:href="@{/assets/img/favicon.png}" />
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" />
<link rel="stylesheet" type="text/css" th:href="@{/webjars/font-awesome/css/all.min.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap-icons/font/bootstrap-icons.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/style.css}" />
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
<style>
table{
width:100%;
}
table td, table th {
border: 1px solid grey;
}
table th {
background: #eee;
}
.pagination-div{
user-select: none;
}
.pagination-div span{
border-radius:3px;
border:1px solid #999;
padding:5px;
margin:10px 0px 0px 10px;
display:inline-block
}
span.selected{
background:#ccf;
}
</style>
</head>
<body>
<h2>Employees</h2>
<div class="my-3 ">
<div class="row d-flex flex-row">
<form th:action="@{/employees}" id="searchForm" >
<div class="row">
<div class="col-sm-8">
<div class="col-md-12 mt-2">
<div class="search">
<i class="fa fa-search"></i>
<input id="keyword" type="search" name="keyword" th:value="${keyword}" required class="form-control"
placeholder="Enter keyword">
<button type="submit" class="btn btn-secondary">搜索</button>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="col-md-12 input-group mt-2">
<div class="input-group-prepend">
<label class="input-group-text" for="pageSize">每页显示行数:</label>
</div>
<select form="searchForm" name="size" th:value="${pageSize}" onchange="changePageSize()" class="size-select"
id="pageSize">
<option th:each="s : ${ {10, 25, 50} }" th:value="${s}" th:text="${s}" th:selected="${s == pageSize}"></option>
</select>
</div>
</div>
<div class="col-sm-1">
<div class="col-md-12 mt-2">
<button id="btnClear" class="btn btn-info">重置</button>
</div>
</div>
</div>
</form>
</div>
</div>
<table>
<tr><th>Id</th>
<th>Name</th>
<th>Department</th>
<th>Salary</th>
</tr>
<tr th:each="employee : ${page.content}">
<td th:text="${employee.id}"></td>
<td th:text="${employee.name}"></td>
<td th:text="${employee.dept}"></td>
<td th:text="${employee.salary}"></td>
</tr>
</table>
<div class="pagination-div">
<span th:if="${page.hasPrevious()}">
<a th:href="@{/employees(page=${page.number-1},size=${page.size})}">Previous</a>
</span>
<th:block th:each="i: ${#numbers.sequence(0, page.totalPages - 1)}">
<span th:if="${page.number == i}" class="selected">[[${i}+1]]</span>
<span th:unless="${page.number == i}">
<a th:href="@{/employees(page=${i},size=${page.size})}">[[${i}+1]]</a>
</span>
</th:block>
<span th:if="${page.hasNext()}">
<a th:href="@{/employees(page=${page.number+1},size=${page.size})}">Next</a>
</span>
</div>
<div class="row">
<div class="col-sm-6">
<div th:if="${page.totalPages > 0}">
总计<span th:text="${page.totalElements}">99</span>行,当前显示<span th:text="(${page.number} )*${page.size} +1">1</span> -
<span th:text="(${page.number} )*${page.size} +${page.numberOfElements}">5</span>行 总计<span th:text="${page.totalPages}">99</span>页
</div>
</div>
<div class="col-sm-6">
<nav aria-label="Pagination" th:if="${page.totalPages > 0}">
<ul class="pagination justify-content-center">
<li class="page-item" th:classappend="${page.number == 0} ? 'disabled'">
<a class="page-link"
th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +'0'+ '&size=' + ${page.size}}"
title="First Page" rel="First Page">
最前页
</a>
</li>
<li class="page-item font-weight-bold" th:classappend="${page.number == 0} ? 'disabled'">
<a class="page-link"
th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number - 1} + '&size=' + ${page.size}}"
title="Previous Page" rel="Previous Page">
前一页
</a>
</li>
<li class="page-item disabled" th:if="${page.number - 2 > 0}">
<a class="page-link" href="#">...</a>
</li>
<li
th:each="i : ${#numbers.sequence(page.number > 2 ? page.number - 2 : 0, page.number + 2 < page.totalPages ? page.number + 2 : page.totalPages-1)}"
class="page-item" th:classappend="${i == page.number} ? 'active'">
<a class="page-link"
th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${i} + '&size=' + ${page.size}}"
th:title=${i+1} th:rel=${i+1}>
[[${i+1} ]]
</a>
</li>
<li class="page-item disabled" th:if="${page.number + 2 < page.totalPages}">
<a class="page-link" href="#">...</a>
</li>
<li class="page-item font-weight-bold" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
<a class="page-link"
th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' + ${page.number + 1} + '&size=' + ${page.size}}"
title="Next Page" rel="Next Page">
后一页
</a>
</li>
<li class="page-item" th:classappend="${page.number == page.totalPages-1} ? 'disabled'">
<a class="page-link"
th:href="@{'/employees?' + ${keyword!=null && keyword!=''? 'keyword=' + keyword + '&' : ''} + 'page=' +${page.totalPages-1}+ '&size=' + ${page.size}}"
title="Last Page" rel="Last Page">
最后页
</a>
</li>
</ul>
</nav>
</div>
</div>
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
class="bi bi-arrow-up-short"></i></a>
<script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}"></script>
<script type="text/javascript" th:src="@{/assets/js/main.js}" ></script>
<script type="text/javascript">
$(document).ready(function () {
$(".btn-delete").on("click", function (e) {
e.preventDefault();
link = $(this);
tutorialTitle = link.attr("tutorialTitle");
$("#yesBtn").attr("href", link.attr("href"));
$("#confirmText").html("Do you want to delete the Tutorial \<strong\>" + tutorialTitle + "\<\/strong\>?");
var myModal = new bootstrap.Modal(document.getElementById('confirmModal'), {
keyboard: false
});
myModal.toggle();
});
$("#btnClear").on("click", function (e) {
e.preventDefault();
$("#keyword").text("");
window.location = "[[@{/employees}]]";
});
});
function changePageSize() {
$("#searchForm").submit();
}
</script>
</body>
</html>
示例项目
https://www.logicbig.com/tutorials/spring-framework/spring-data/pagination-with-thymeleaf/spring-data-jpa-pagination-with-thymeleaf.zip