Spring Boot Offset分页、Keyset 分页与Thymeleaf教程

欢迎,在本教程中,我们将解释弹簧启动应用程序中的分页,为此,我们将使用百里香叶。

1. 简介

在继续本教程之前,我们将了解常用术语,例如 Spring Boot、龙目岛、百里香叶和分页简介。

1.1 弹簧启动

  • Spring 启动是一个模块,它为 Spring框架提供快速的应用程序开发功能,包括自动配置、独立代码和生产就绪代码
  • 它创建打包为jar的应用程序,并使用嵌入式 servlet 容器(如 Tomcat、Jetty 或 Undertow)直接启动。因此,无需部署战争文件
  • 它通过提供初学者模板简化了 maven 配置,并有助于解决依赖项冲突。它会自动识别所需的依赖项并将其导入应用程序中
  • 它有助于删除样板代码、额外的注释和 xml 配置
  • 它提供强大的批处理并管理其余端点
  • 它提供了一个高效的jpa-starter库,可以有效地将应用程序与关系数据库连接起来
  • 它提供微服务架构和云配置,以集中方式管理所有与应用程序相关的配置属性

1.2 龙目岛

  • 龙目岛只不过是一个小型库,它减少了项目中样板Java代码的数量
  • 使用龙目岛注释自动生成对象的吸气剂和二传手
  • 通过注释处理器 API 挂钩
  • 在 Java 编译器继续之前,原始源代码将传递给 Lombok 进行代码生成。因此,与Java编译器一起生成正确编译的Java代码
  • 在文件夹下,您可以查看已编译的类文件target/classes
  • 可以与Maven,Gradle IDE等一起使用。

1.2.1 龙目岛的特点

特征
val 局部变量声明为final
var 可变局部变量
@Slf4J 创建 SLF4J 记录器
@Cleanup 将调用块中的资源close()finally
@Getter 为所有属性创建 getter 方法
@Setter 为所有非最终属性创建二传手
@EqualsAndHashCode
  • 生成和的实现equals(Object other)hashCode()
  • 默认情况下将使用所有非静态、非瞬态属性
  • 可以选择排除特定属性
@ToString
  • 生成类名的字符串,每个字段用逗号分隔
  • 包含字段名称的可选参数
  • 包含对超方法的调用的可选参数toString
@NoArgsConstructor
  • 生成无参数构造函数
  • 如果有最终字段,将导致编译器错误
  • 可以选择强制,这将使用 0/false/null var 初始化最终字段 – 可变局部变量
@RequiredArgsContructor
  • 为所有标记为 或 的字段生成构造函数final@NonNull
  • 构造函数将抛出 aif 任何字段为空值 – 声明局部变量NullPointerException@NonNullfinal
@AllArgsConstructor
  • 为类的所有属性生成构造函数
  • 任何属性都将具有空检查@NotNull
@Data
  • 为 POJO 生成典型的样板代码
  • 结合–@Getter@Setter@ToString@EqualsAndHashCode@RequiredArgsConstructor
  • 如果显式声明了构造函数,则不会生成构造函数
@Builder
  • 实现用于对象创建的生成器模式
@Value
  • 的不可变变体@Data
  • 所有字段都是创建的,默认情况下privatefinal

1.3 百里香叶

  • Thymeleaf是用于 Web 应用程序的服务器端 Java 模板引擎
  • 它处理HTML,XML,JS,CSS和简单的文本,为Web应用程序带来优雅的设计
  • 要使用百里香叶,您必须在模板中定义依赖关系并提及库spring-boot-starter-thymeleafpom.xmlxmlns:th="https://thymeleaf.org"

1.4 分页

  • 分页是将数据划分为合适的块以节省资源的过程
  • 为了在 Spring boot 应用程序中执行分页,我们将使用接口提供额外的方法来通过使用 spring boot 中的分页来检索结果(即从数据中获取第一页,每个大小有 10 个项目等)。PagingAndSortingRepository

2. 春季启动分页与百里香叶教程

这是实现本教程的系统指南,但在进一步讨论之前,我假设您了解 Spring 启动基础知识。

2.1 申请先决条件

从本教程开始,我们希望您目前在他们最喜欢的选择 IDE 中安装了龙目岛插件。如果有人需要在IntelliJ IDE上完成龙目岛安装,请观看视频。要在 Eclipse IDE 上进行安装,请观看视频。

2.2 使用的工具与项目结构

我们正在使用 Eclipse Kepler SR2、JDK 8 和 Maven。如果您对应该在哪里创建相应的文件或文件夹感到困惑,让我们回顾一下 Spring 引导应用程序的项目结构。

图1:项目结构

让我们开始构建应用程序!

3. 创建 Spring 引导应用程序

以下是开发应用程序所涉及的步骤。

3.1 Maven 依赖

在这里,我们指定了Spring Boot,Spring Data JPA,Thymeleaf,H2数据库,Faker和Lombok的依赖关系。Maven 将自动解析其他依赖项。更新后的文件将具有以下代码。

绒球.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.springboot.thymeleaf.pagination</groupId>
    <artifactId>SpringbootThymeleafPaginationV2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <name>Springboot thymeleaf pagination tutorial</name>
    <description>A springboot tutorial to show the pagination in thymeleaf</description>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>
 
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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-thymeleaf</artifactId>
        </dependency>
        <!-- embedded database (h2) dependency. -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- lombok dependency. -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- faker dependency to generate some random data. -->
        <dependency>
            <groupId>com.github.javafaker</groupId>
            <artifactId>javafaker</artifactId>
            <version>1.0.2</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.2 应用程序属性

在 location: 创建一个新的属性文件,并向其添加以下代码。SpringbootThymeleafPaginationV2/src/main/resources/

应用程序属性

01
02
03
04
05
06
07
08
09
10
11
12
13
14
server.port=10091
spring.application.name=springboot-thymeleaf-pagination-v2
# h2 database settings
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
# db-creation settings
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
## browser url for h2 console - http://localhost:10091/h2-console
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

3.3 Java类

让我们编写此应用程序中涉及的所有 java 类。

3.3.1 实现/主类

将以下代码添加到主类,以便从 main 方法启动应用程序。永远记住,Spring 引导应用程序的入口点是包含注释和静态 main 方法的类。@SpringBootApplication

春靴百里香叶分页.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package com.springboot.thymeleaf.pagination.v2;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
// Causes Lombok to generate a logger field.
@Slf4j
// Serves two purposes i.e. configuration and bootstrapping.
@SpringBootApplication
public class SpringbootThymeleafPagination {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringbootThymeleafPagination.class,args);
        log.info("Springboot Pagination with Thymeleaf application is started successfully .");
    }
}

3.3.2 模型类

将以下代码添加到模型类中。Resident

居民.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.springboot.thymeleaf.pagination.v2.model;
 
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
 
import javax.persistence.*;
import java.time.LocalDate;
 
@Entity
@Table(name = "resident")
// Causes Lombok to generate toString(),equals(),hashCode(),getter() & setter(),and Required arguments constructor in one go.
@Data
// Causes Lombok to implement the Builder design pattern for the Pojo class.
// Usage can be seen in DefaultResidentsLoader.java -> createNewResident() method.
@Builder
// Causes Lombok to generate a constructor with no parameters.
@NoArgsConstructor
// Causes Lombok to generate a constructor with 1 parameter for each field in your class.
@AllArgsConstructor
@Component
public class Resident {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    int id;
    @Column(name = "full_name",nullable = false)
    String fullName;
    @Column(name = "age",nullable = false)
    int age;
    @Column(name = "gender",nullable = false)
    String gender;
    @Column(name = "phone_number",unique = true)
    String phoneNumber;
    @Column(name = "email_address",nullable = false,unique = true)
    String emailAddress;
    @Column(name = "date_of_birth",nullable = false)
    LocalDate dateOfBirth;
    @Column(name = "home_address")
    String homeAddress;
    @Column(name = "nationality")
    String nationality;
    @Column(name = "first_language")
    String firstLanguage;
 
}

3.3.3 配置类

将以下代码添加到将返回该对象的 Bean 对象的 Bean 类中。此对象的用法可以在 theclass 中看到,该类用于在应用程序启动时将虚拟数据加载到数据库中。fakerDefaultResidentsLoader.java

豆子配置.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package com.springboot.thymeleaf.pagination.v2.configuration;
 
import com.github.javafaker.Faker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.util.Locale;
 
@Configuration
public class BeanConfiguration {
 
    @Bean
    public Faker faker() {
        return new Faker(new Locale("en-US"));
    }
}

3.3.4 数据访问对象接口

将以下代码添加到扩展接口的接口中。PagingAndSortingRepository

居民存储库.java

01
02
03
04
05
06
07
08
09
10
package com.springboot.thymeleaf.pagination.v2.repository;
 
import com.springboot.thymeleaf.pagination.v2.model.Resident;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
 
@Repository
public interface ResidentRepository extends PagingAndSortingRepository<Resident,Integer> {
 
}

3.3.5 服务类

将以下代码添加到服务类中,我们将在其中调用 DAO 接口方法将数据保存到数据库中,并从数据库中获取数据。

居民服务.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.springboot.thymeleaf.pagination.v2.service;
 
import com.springboot.thymeleaf.pagination.v2.model.Resident;
import com.springboot.thymeleaf.pagination.v2.repository.ResidentRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
 
// Causes Lombok to generate a logger field.
@Slf4j
@Service
public class ResidentService {
 
    @Autowired
    private ResidentRepository repository;
 
    public void save(final Resident resident) {
        repository.save(resident);
    }
 
    public long getResidentsCount() {
        log.info("Finding the total count of residents from the dB.");
        return repository.count();
    }
 
    public Page getPaginatedResidents(final int pageNumber, final int pageSize) {
        log.info("Fetching the paginated residents from the dB.");
        final Pageable pageable = PageRequest.of(pageNumber - 1,pageSize);
        return repository.findAll(pageable);
    }
}

3.3.6 引导类

将以下代码添加到引导类,以便在应用程序启动时将虚拟数据保存到数据库中。这些数据将保存在 H2 数据库中。

默认居民加载器.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.springboot.thymeleaf.pagination.v2.bootstrap;
 
import com.github.javafaker.Faker;
import com.springboot.thymeleaf.pagination.v2.model.Resident;
import com.springboot.thymeleaf.pagination.v2.service.ResidentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
 
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.Random;
 
// Causes Lombok to generate a logger field.
@Slf4j
// Causes Lombok to generate a constructor with 1 parameter for each field that requires special handling.
@RequiredArgsConstructor
@Component
public class DefaultResidentsLoader implements CommandLineRunner {
 
    private static final String[] GENDER = {"Male""Female""Transgender""Not to specify"};
    private static final Random RANDOM = new Random();
 
    private final ResidentService service;
    private final Faker faker;
 
    @Override
    public void run(String... args) throws Exception {
        loadResidentsData();
    }
 
    private void loadResidentsData() {
        if (service.getResidentsCount() == 0) {
            for (int x = 0; x < 100; x++) {
                service.save(createNewResident());
            }
            log.info("Default residents are successfully saved in the database.");
        else {
            log.info("Default residents are already present in the database.");
        }
    }
 
    private Resident createNewResident() {
        final String firstName = faker.name().firstName();
        final String lastName = faker.name().lastName();
        final String emailAddress = firstName.toLowerCase() + "." + lastName.toLowerCase() + "@company.com";
        final LocalDate birthdate = faker.date().birthday(2558).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        final int age = Period.between(birthdate,LocalDate.now()).getYears();
        final String gender = GENDER[RANDOM.nextInt(GENDER.length)];
 
        return Resident.builder()
                .fullName(firstName + " " + lastName)
                .age(age)
                .gender(gender)
                .phoneNumber(faker.phoneNumber().cellPhone())
                .emailAddress(emailAddress)
                .dateOfBirth(birthdate)
                .homeAddress(faker.address().fullAddress())
                .nationality(faker.nation().nationality())
                .firstLanguage(faker.nation().language())
                .build();
    }
}

3.3.7 索引控制器类

将以下代码添加到旨在处理传入请求的控制器类中。该类是用注释注释的,该方法将返回应用程序的页面。@ControllerHTTP GETindex

ResidentController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.springboot.thymeleaf.pagination.v2.controller;
 
import com.springboot.thymeleaf.pagination.v2.dto.ResponseDto;
import com.springboot.thymeleaf.pagination.v2.model.Resident;
import com.springboot.thymeleaf.pagination.v2.service.ResidentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 
import java.util.HashMap;
import java.util.Map;
 
// Causes Lombok to generate a logger field.
@Slf4j
@Controller
public class ResidentController {
 
    private static final int DEFAULT_PAGE_NUMBER = 1;
    private static final int DEFAULT_PAGE_SIZE = 10;
 
    @Autowired
    private ResidentService service;
 
    // URL - http://localhost:10091/
    @GetMapping(value = "/")
    public String viewIndexPage() {
        log.info("Redirecting the index page to the controller method for fetching the residents in a paginated fashion.");
        return "redirect:residents/paginated/" + DEFAULT_PAGE_NUMBER + "/" + DEFAULT_PAGE_SIZE;
    }
 
    @GetMapping(value = "/residents/paginated/{page}/{page-size}")
    public String getPaginatedResidents(@PathVariable(name = "page"final int pageNumber,
                                        @PathVariable(name = "page-size"final int pageSize, final Model model) {
        log.info("Getting the residents in a paginated way for page-number = {} and page-size = {}.",pageNumber,pageSize);
        final Page<Resident> paginatedResidents = service.getPaginatedResidents(pageNumber,pageSize);
        model.addAttribute("responseEntity",createResponseDto(paginatedResidents,pageNumber));
        return "index";
    }
 
    private ResponseDto createResponseDto(final Page<Resident> residentPage, final int pageNumber) {
        final Map<String,Integer> page = new HashMap<>();
        page.put("currentPage",pageNumber);
        /*
         Here we are fetching the total number of records from the Page interface of the Spring itself.
         We can also customize this logic based on the total number of elements retrieved from the query.
        */
        page.put("totalPages",residentPage.getTotalPages());
        page.put("totalElements",(int) residentPage.getTotalElements());
        return ResponseDto.create(residentPage.getContent(),page);
    }
}

4. 百里香叶的变化

我们将创建一个简单的 HTML 页面,该页面将以较小的块(即分页方法)在浏览器上显示居民。在 位置 : 创建一个新的 HTML 文件,并向其添加以下代码。SpringbootThymeleafPaginationV2/src/main/resources/templates/

索引.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Index page</title>
    <style type="text/css">
        th {
            text-align: center;
            font-weight: bold;
            border-top: none !important;
        }
 
        th,td {
            white-space: nowrap;
        }
 
        .mt-20 {
            margin-top: 20px;
        }
 
        .table-alignment {
            margin-left: -200px;
        }
    </style>
</head>
<body>
 
<div class="container">
    <h3 class="text-info text-center mt-20">Pagination Example : Residents</h3>
 
    <table class="table table-striped table-alignment mt-20 text-center">
        <thead id="residentsTable">
        <tr>
            <th>Id</th>
            <th>Full name</th>
            <th>Age</th>
            <th>Gender</th>
            <th>Phone Number</th>
            <th>Email Address</th>
            <th>Date of Birth</th>
            <th>Home Address</th>
            <th>Nationality</th>
            <th>First Language</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="resident : ${responseEntity.residents}">
            <td th:text="${resident.id}"></td>
            <td th:text="${resident.fullName}"></td>
            <td th:text="${resident.age}"></td>
            <td th:text="${resident.gender}"></td>
            <td th:text="${resident.phoneNumber}"></td>
            <td th:text="${resident.emailAddress}"></td>
            <td th:text="${resident.dateOfBirth}"></td>
            <td th:text="${resident.homeAddress}"></td>
            <td th:text="${resident.nationality}"></td>
            <td th:text="${resident.firstLanguage}"></td>
        </tr>
        </tbody>
    </table>
 
    <!-- Pagination control -->
    <!-- Hardcoding the default page-size as 10. User can create a dropdown to select the different page-sizes. -->
    <div class="row">
        <div th:if="${responseEntity.page['totalPages'] > 1}">
            <div>
                Total Items: [[${responseEntity.page['totalPages']}]]
            </div>
            <div>
                <span th:each="i: ${#numbers.sequence(1,responseEntity.page['totalPages'])}">
                    <a th:href="@{'/residents/paginated/' + ${i} + '/10'}"
                       th:if="${responseEntity.page['currentPage'] != i}">[[${i}]]</a>
                    <span th:unless="${responseEntity.page['currentPage'] != i}">[[${i}]]</span>
                </span>
            </div>
            <div>
                <a th:href="@{'/residents/paginated/' + ${responseEntity.page['currentPage'] + 1} + '/10'}"
                   th:if="${responseEntity.page['currentPage'] < responseEntity.page['totalPages']}">
                    Next
                </a>
                <span th:unless="${responseEntity.page['currentPage'] < responseEntity.page['totalPages']}">Next</span>
            </div>
            <div>
                <a th:href="@{'/residents/paginated/' + ${responseEntity.page['totalPages']} + '/10'}"
                   th:if="${responseEntity.page['currentPage'] < responseEntity.page['totalPages']}">
                    Last
                </a>
                <span th:unless="${responseEntity.page['currentPage'] < responseEntity.page['totalPages']}">Last</span>
            </div>
        </div>
    </div>
</div>
 
</body>
 
</html>

5. 运行应用程序

要执行应用程序,请右键单击类。SpringbootThymeleafPagination.javaRun As -> Java Application

图 2:运行应用程序

6. 项目演示

打开您选择的浏览器并点击以下 URL。结果将以分页方式显示(即较小的块),您可以单击页码以根据页码检索结果。

图3:使用百里香叶在春季启动中进行分页

这就是本教程的全部内容,我希望这篇文章能为您提供所需的任何帮助。快乐学习,不要忘记分享!

7. 总结

在本节中,您了解到,

  • Spring Boot,Thymeleaf,龙目岛及其功能,以及分页概念
  • Spring Boot 中的分页实现并使用 Thymeleaf 在浏览器上显示元素

您可以在“下载”部分中将样例应用程序下载为 Eclipse 项目。

 8. 下载日食项目

这是使用百里香叶进行Spring Boot分页的一个例子。

下载 您可以在此处下载
 此示例的完整源代码:Spring 引导

 8. Keyset 分页

存储库

package com.springboot.thymeleaf.pagination.v2.repository;

import com.springboot.thymeleaf.pagination.v2.model.Resident;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ResidentRepository extends PagingAndSortingRepository<Resident,Long> {

    @Query(value = "SELECT * FROM resident AS r WHERE r.id > ?1 ORDER BY r.id ASC LIMIT ?2",nativeQuery = true)
    List<Resident> fetchAllAscNext(Long id,Long limit);

    @Query(value = "SELECT * FROM resident AS r WHERE r.id < ?1 ORDER BY r.id DESC LIMIT ?2",nativeQuery = true)
    List<Resident> fetchAllAscPrevious(Long id,Long limit);

    @Query(value = "SELECT count(*)  FROM resident",nativeQuery = true)
    public Long fetchCount();

    @Query(value = "SELECT min(id)  FROM resident",nativeQuery = true)
    public Long fetchMinId();

    @Query(value = "SELECT max(id)  FROM resident",nativeQuery = true)
    public Long fetchMaxId();
}

控制器

package com.springboot.thymeleaf.pagination.v2.controller;

import com.springboot.thymeleaf.pagination.v2.model.Resident;
import com.springboot.thymeleaf.pagination.v2.repository.ResidentRepository;
import com.springboot.thymeleaf.pagination.v2.service.ResidentService;
import java.util.Collections;
import lombok.extern.slf4j.Slf4j;
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 java.util.List;
import org.springframework.web.bind.annotation.RequestParam;

// Causes Lombok to generate a logger field.
@Slf4j
@Controller
public class ResidentController {

    private static final int DEFAULT_PAGE_NUMBER = 1;
    private static final int DEFAULT_PAGE_SIZE = 10;

    @Autowired
    private ResidentService service;

    @Autowired
    private ResidentRepository repository;

    @GetMapping(value = "/")
    public String viewIndexPage() {
        log.info("Redirecting the index page to the controller method for fetching the residents in a paginated fashion.");
        return "redirect:residents/paginated/" + DEFAULT_PAGE_NUMBER + "/" + DEFAULT_PAGE_SIZE;
    }

    @GetMapping("/residents")
    public String getPaginatedResidents(Model model,@RequestParam(required = false) String keyword,@RequestParam(defaultValue = "next") String dir,@RequestParam(defaultValue = "0") Long page,@RequestParam(defaultValue = "10") Long size) {
        log.info("Getting the residents in a paginated way for page-number = {} and page-size = {}.",page,size);
        if (dir.equals("next")) {
            List<Resident> fetchAllAscNext = repository.fetchAllAscNext(page,size);
            model.addAttribute("responseEntity",fetchAllAscNext);
            model.addAttribute("max",fetchAllAscNext.get(fetchAllAscNext.size() - 1).getId());
            model.addAttribute("min",fetchAllAscNext.get(0).getId());
        } else {
            List<Resident> fetchAllAscPrevious = repository.fetchAllAscPrevious(page,size);
            Collections.reverse(fetchAllAscPrevious);
            model.addAttribute("responseEntity",fetchAllAscPrevious);
            model.addAttribute("max",fetchAllAscPrevious.get(fetchAllAscPrevious.size() - 1).getId());
            model.addAttribute("min",fetchAllAscPrevious.get(0).getId());
        }
        model.addAttribute("fetchCount",repository.fetchCount());
        model.addAttribute("fetchMinId",repository.fetchMinId());
        model.addAttribute("fetchMaxId",repository.fetchMaxId());
        return "index";
    }

}

视图

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Index page</title>
        <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
        <style type="text/css">
            th {
                text-align: center;
                font-weight: bold;
                border-top: none !important;
            }

            th,td {
                white-space: nowrap;
            }

            .mt-20 {
                margin-top: 20px;
            }

            .table-alignment {
                margin-left: -200px;
            }
        </style>
    </head>
    <body>

        <div class="container">
            <h3 class="text-info text-center mt-20">Pagination Example : Residents</h3>

            <table class="table table-striped table-alignment mt-20 text-center">
                <thead id="residentsTable">
                    <tr>
                        <th>Id</th>
                        <th>Full name</th>
                        <th>Age</th>
                        <th>Gender</th>
                        <th>Phone Number</th>
                        <th>Email Address</th>
                        <th>Date of Birth</th>
                        <th>Home Address</th>
                        <th>Nationality</th>
                        <th>First Language</th>
                    </tr>
                </thead>
                <tbody>
                    <tr th:each="resident : ${responseEntity}">
                        <td th:text="${resident.id}"></td>
                        <td th:text="${resident.fullName}"></td>
                        <td th:text="${resident.age}"></td>
                        <td th:text="${resident.gender}"></td>
                        <td th:text="${resident.phoneNumber}"></td>
                        <td th:text="${resident.emailAddress}"></td>
                        <td th:text="${resident.dateOfBirth}"></td>
                        <td th:text="${resident.homeAddress}"></td>
                        <td th:text="${resident.nationality}"></td>
                        <td th:text="${resident.firstLanguage}"></td>
                    </tr>
                </tbody>
            </table>

            <!-- Pagination control -->
            <!-- Hardcoding the default page-size as 10. User can create a dropdown to select the different page-sizes. -->
            <div class="row">
                <div>
                    <div>
                        Total Items: [[${fetchCount}]]
                    </div>
                    <div>
                        <a th:if="${min > fetchMinId}"
                           th:href="@{'/residents/?page='+${min}+'&size=10&dir=prev'}" >
                            Prev
                        </a>
                        <span th:unless="${min > fetchMinId}">Prev</span>
                    </div>
                    <div>
                        <a th:if="${max < fetchMaxId}"
                           th:href="@{'/residents/?page='+${max}+'&size=10&dir=next'}" >
                            Next
                        </a>
                        <span th:unless="${max < fetchMaxId}">Next</span>
                    </div>

                </div>
            </div>
        </div>

    </body>

</html>

原文地址:https://blog.csdn.net/allway2

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下