在本教程中,我将演示如何通过分页显示Thymeleaf中的企业客户列表。
1 –项目结构
2 –项目依赖性
除了正常的Spring依赖关系之外,我们还添加Thymeleaf和hsqldb,因为我们使用的是嵌入式数据库。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.michaelcgood</groupId>
<artifactId>michaelcgood-pagingandsorting</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>PagingAndSortingRepositoryExample</name>
<description>Michael C Good - PagingAndSortingRepository</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3 –型号
我们为客户定义以下字段:
- 唯一标识符
- 客户名称
- 客户地址
- 当前发票上的欠款
getter和setter在Spring Tool Suite中快速生成。
要将此模型注册到@SpringBootApplication,需要@Entity批注。
ClientModel.java
package com.michaelcgood.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class ClientModel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getCurrentInvoice() {
return currentInvoice;
}
public void setCurrentInvoice(Integer currentInvoice) {
this.currentInvoice = currentInvoice;
}
private String name;
private String address;
private Integer currentInvoice;
}
与ClientModel不同,PagerModel只是一个POJO(普通的旧Java对象)。 没有导入,因此没有注释。 此PagerModel仅用于帮助我们网页上的分页。 阅读Thymeleaf模板并查看演示图片后,请重新访问此模型。 当您在上下文中考虑它时,PagerModel更有意义。
PagerModel.java
package com.michaelcgood.model;
public class PagerModel {
private int buttonsToShow = 5;
private int startPage;
private int endPage;
public PagerModel(int totalPages, int currentPage, int buttonsToShow) {
setButtonsToShow(buttonsToShow);
int halfPagesToShow = getButtonsToShow() / 2;
if (totalPages <= getButtonsToShow()) {
setStartPage(1);
setEndPage(totalPages);
} else if (currentPage - halfPagesToShow <= 0) {
setStartPage(1);
setEndPage(getButtonsToShow());
} else if (currentPage + halfPagesToShow == totalPages) {
setStartPage(currentPage - halfPagesToShow);
setEndPage(totalPages);
} else if (currentPage + halfPagesToShow > totalPages) {
setStartPage(totalPages - getButtonsToShow() + 1);
setEndPage(totalPages);
} else {
setStartPage(currentPage - halfPagesToShow);
setEndPage(currentPage + halfPagesToShow);
}
}
public int getButtonsToShow() {
return buttonsToShow;
}
public void setButtonsToShow(int buttonsToShow) {
if (buttonsToShow % 2 != 0) {
this.buttonsToShow = buttonsToShow;
} else {
throw new IllegalArgumentException("Must be an odd value!");
}
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
@Override
public String toString() {
return "Pager [startPage=" + startPage + ", endPage=" + endPage + "]";
}
}
4 –储存库
PagingAndSortingRepository是CrudRepository的扩展。 唯一的区别是,它允许您对实体进行分页。 注意,我们用@Repository注释了接口,以使其对@SpringBootApplication可见。
ClientRepository.java
package com.michaelcgood.dao;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.michaelcgood.model.ClientModel;
@Repository
public interface ClientRepository extends PagingAndSortingRepository<ClientModel,Long> {
}
5 –控制器
我们在课程开始时定义一些变量。 我们只想一次显示3个页面按钮。 初始页面是结果的第一页,页面上的初始项目数是5,并且用户能够每页获得5或10个结果。
我们使用addtorepository()方法将一些示例值添加到我们的存储库中,该方法将在此类中进一步定义。 使用addtorepository method(),我们将几个“客户端”添加到我们的存储库中,其中许多都是帽子公司,因为我没有想法。
这里使用ModelAndView而不是Model。 而是使用ModelAndView,因为它既是ModelMap也是视图对象的容器。 它允许控制器将两个值作为单个值返回。 这是我们正在做的事情所希望的。
ClientController.java
package com.michaelcgood.controller;
import java.util.Optional;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.michaelcgood.model.PagerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import com.michaelcgood.dao.ClientRepository;
import com.michaelcgood.model.ClientModel;
@Controller
public class ClientController {
private static final int BUTTONS_TO_SHOW = 3;
private static final int INITIAL_PAGE = 0;
private static final int INITIAL_PAGE_SIZE = 5;
private static final int[] PAGE_SIZES = { 5, 10};
@Autowired
ClientRepository clientrepository;
@GetMapping("/")
public ModelAndView homepage(@RequestParam("pageSize") Optional<Integer> pageSize,
@RequestParam("page") Optional<Integer> page){
if(clientrepository.count()!=0){
;//pass
}else{
addtorepository();
}
ModelAndView modelAndView = new ModelAndView("index");
//
// Evaluate page size. If requested parameter is null, return initial
// page size
int evalPageSize = pageSize.orElse(INITIAL_PAGE_SIZE);
// Evaluate page. If requested parameter is null or less than 0 (to
// prevent exception), return initial size. Otherwise, return value of
// param. decreased by 1.
int evalPage = (page.orElse(0) < 1) ? INITIAL_PAGE : page.get() - 1;
// print repo
System.out.println("here is client repo " + clientrepository.findAll());
Page<ClientModel> clientlist = clientrepository.findAll(new PageRequest(evalPage, evalPageSize));
System.out.println("client list get total pages" + clientlist.getTotalPages() + "client list get number " + clientlist.getNumber());
PagerModel pager = new PagerModel(clientlist.getTotalPages(),clientlist.getNumber(),BUTTONS_TO_SHOW);
// add clientmodel
modelAndView.addObject("clientlist",clientlist);
// evaluate page size
modelAndView.addObject("selectedPageSize", evalPageSize);
// add page sizes
modelAndView.addObject("pageSizes", PAGE_SIZES);
// add pager
modelAndView.addObject("pager", pager);
return modelAndView;
}
public void addtorepository(){
//below we are adding clients to our repository for the sake of this example
ClientModel widget = new ClientModel();
widget.setAddress("123 Fake Street");
widget.setCurrentInvoice(10000);
widget.setName("Widget Inc");
clientrepository.save(widget);
//next client
ClientModel foo = new ClientModel();
foo.setAddress("456 Attorney Drive");
foo.setCurrentInvoice(20000);
foo.setName("Foo LLP");
clientrepository.save(foo);
//next client
ClientModel bar = new ClientModel();
bar.setAddress("111 Bar Street");
bar.setCurrentInvoice(30000);
bar.setName("Bar and Food");
clientrepository.save(bar);
//next client
ClientModel dog = new ClientModel();
dog.setAddress("222 Dog Drive");
dog.setCurrentInvoice(40000);
dog.setName("Dog Food and Accessories");
clientrepository.save(dog);
//next client
ClientModel cat = new ClientModel();
cat.setAddress("333 Cat Court");
cat.setCurrentInvoice(50000);
cat.setName("Cat Food");
clientrepository.save(cat);
//next client
ClientModel hat = new ClientModel();
hat.setAddress("444 Hat Drive");
hat.setCurrentInvoice(60000);
hat.setName("The Hat Shop");
clientrepository.save(hat);
//next client
ClientModel hatB = new ClientModel();
hatB.setAddress("445 Hat Drive");
hatB.setCurrentInvoice(60000);
hatB.setName("The Hat Shop B");
clientrepository.save(hatB);
//next client
ClientModel hatC = new ClientModel();
hatC.setAddress("446 Hat Drive");
hatC.setCurrentInvoice(60000);
hatC.setName("The Hat Shop C");
clientrepository.save(hatC);
//next client
ClientModel hatD = new ClientModel();
hatD.setAddress("446 Hat Drive");
hatD.setCurrentInvoice(60000);
hatD.setName("The Hat Shop D");
clientrepository.save(hatD);
//next client
ClientModel hatE = new ClientModel();
hatE.setAddress("447 Hat Drive");
hatE.setCurrentInvoice(60000);
hatE.setName("The Hat Shop E");
clientrepository.save(hatE);
//next client
ClientModel hatF = new ClientModel();
hatF.setAddress("448 Hat Drive");
hatF.setCurrentInvoice(60000);
hatF.setName("The Hat Shop F");
clientrepository.save(hatF);
}
}
6 – Thymeleaf模板
在Thymeleaf模板中,需要注意的两个最重要的事情是:
- 胸腺标准方言
- Java脚本
就像在CrudRepository中一样,我们使用th:each =” clientlist:$ {clientlist}”遍历PagingAndSortingRepository。 除了不是存储库中的每个项目都是Iterable之外,该项目都是页面。
使用select class =“ form-control pagination” id =“ pageSizeSelect”,我们允许用户选择5或10的页面大小。我们在Controller中定义了这些值。
接下来是允许用户浏览各个页面的代码。 这是我们的PagerModel进入使用的地方。
changePageAndSize()函数是JavaScript函数,它将在用户更改页面大小时更新页面大小。
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<!-- CSS INCLUDE -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous"></link>
<!-- EOF CSS INCLUDE -->
<style>
.pagination-centered {
text-align: center;
}
.disabled {
pointer-events: none;
opacity: 0.5;
}
.pointer-disabled {
pointer-events: none;
}
</style>
</head>
<body>
<!-- START PAGE CONTAINER -->
<div class="container-fluid">
<!-- START PAGE SIDEBAR -->
<!-- commented out <div th:replace="fragments/header :: header"> </div> -->
<!-- END PAGE SIDEBAR -->
<!-- PAGE TITLE -->
<div class="page-title">
<h2>
<span class="fa fa-arrow-circle-o-left"></span> Client Viewer
</h2>
</div>
<!-- END PAGE TITLE -->
<div class="row">
<table class="table datatable">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Load</th>
</tr>
</thead>
<tbody>
<tr th:each="clientlist : ${clientlist}">
<td th:text="${clientlist.name}">Text ...</td>
<td th:text="${clientlist.address}">Text ...</td>
<td><button type="button"
class="btn btn-primary btn-condensed">
<i class="glyphicon glyphicon-folder-open"></i>
</button></td>
</tr>
</tbody>
</table>
<div class="row">
<div class="form-group col-md-1">
<select class="form-control pagination" id="pageSizeSelect">
<option th:each="pageSize : ${pageSizes}" th:text="${pageSize}"
th:value="${pageSize}"
th:selected="${pageSize} == ${selectedPageSize}"></option>
</select>
</div>
<div th:if="${clientlist.totalPages != 1}"
class="form-group col-md-11 pagination-centered">
<ul class="pagination">
<li th:class="${clientlist.number == 0} ? disabled"><a
class="pageLink"
th:href="@{/(pageSize=${selectedPageSize}, page=1)}">«</a>
</li>
<li th:class="${clientlist.number == 0} ? disabled"><a
class="pageLink"
th:href="@{/(pageSize=${selectedPageSize}, page=${clientlist.number})}">←</a>
</li>
<li
th:class="${clientlist.number == (page - 1)} ? 'active pointer-disabled'"
th:each="page : ${#numbers.sequence(pager.startPage, pager.endPage)}">
<a class="pageLink"
th:href="@{/(pageSize=${selectedPageSize}, page=${page})}"
th:text="${page}"></a>
</li>
<li
th:class="${clientlist.number + 1 == clientlist.totalPages} ? disabled">
<a class="pageLink"
th:href="@{/(pageSize=${selectedPageSize}, page=${clientlist.number + 2})}">→</a>
</li>
<li
th:class="${clientlist.number + 1 == clientlist.totalPages} ? disabled">
<a class="pageLink"
th:href="@{/(pageSize=${selectedPageSize}, page=${clientlist.totalPages})}">»</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END PAGE CONTENT -->
<!-- END PAGE CONTAINER -->
</div>
<script
src="https://code.jquery.com/jquery-1.11.1.min.js"
integrity="sha256-VAvG3sHdS5LqTT+5A/aeq/bZGa/Uj04xKxY8KM/w9EE="
crossorigin="anonymous"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<script th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function() {
changePageAndSize();
});
function changePageAndSize() {
$('#pageSizeSelect').change(function(evt) {
window.location.replace("/?pageSize=" + this.value + "&page=1");
});
}
/*]]>*/
</script>
</body>
</html>
7 –配置
可以根据您的喜好更改以下属性,但这正是我所希望的环境。
application.properties
#==================================
# = Thymeleaf configurations
#==================================
spring.thymeleaf.check-template-location=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.content-type=text/html
spring.thymeleaf.cache=false
server.contextPath=/
8 –演示
这是主页。
源代码在 Github上
翻译自: https://www.javacodegeeks.com/2017/10/pagingandsortingrepository-use-thymeleaf.html