• 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.0modelVersion>
     
        <groupId>com.springboot.thymeleaf.paginationgroupId>
        <artifactId>SpringbootThymeleafPaginationV2artifactId>
        <version>0.0.1-SNAPSHOTversion>
     
        <name>Springboot thymeleaf pagination tutorialname>
        <description>A springboot tutorial to show the pagination in thymeleafdescription>
     
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.3.4.RELEASEversion>
        parent>
     
        <properties>
            <java.version>1.8java.version>
        properties>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-jpaartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-thymeleafartifactId>
            dependency>
            
            <dependency>
                <groupId>com.h2databasegroupId>
                <artifactId>h2artifactId>
                <scope>runtimescope>
            dependency>
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <scope>providedscope>
            dependency>
            
            <dependency>
                <groupId>com.github.javafakergroupId>
                <artifactId>javafakerartifactId>
                <version>1.0.2version>
            dependency>
        dependencies>
     
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                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 {
     
    }

    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 paginatedResidents = service.getPaginatedResidents(pageNumber, pageSize);
            model.addAttribute("responseEntity", createResponseDto(paginatedResidents, pageNumber));
            return "index";
        }
     
        private ResponseDto createResponseDto(final Page residentPage, final int pageNumber) {
            final Map 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 pagetitle>
        <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 : Residentsh3>
     
        <table class="table table-striped table-alignment mt-20 text-center">
            <thead id="residentsTable">
            <tr>
                <th>Idth>
                <th>Full nameth>
                <th>Ageth>
                <th>Genderth>
                <th>Phone Numberth>
                <th>Email Addressth>
                <th>Date of Birthth>
                <th>Home Addressth>
                <th>Nationalityth>
                <th>First Languageth>
            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>
     
        
        
        <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']}">Nextspan>
                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']}">Lastspan>
                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 分页

    存储库

    1. package com.springboot.thymeleaf.pagination.v2.repository;
    2. import com.springboot.thymeleaf.pagination.v2.model.Resident;
    3. import java.util.List;
    4. import org.springframework.data.jpa.repository.Query;
    5. import org.springframework.data.repository.PagingAndSortingRepository;
    6. import org.springframework.stereotype.Repository;
    7. @Repository
    8. public interface ResidentRepository extends PagingAndSortingRepository {
    9. @Query(value = "SELECT * FROM resident AS r WHERE r.id > ?1 ORDER BY r.id ASC LIMIT ?2",
    10. nativeQuery = true)
    11. List fetchAllAscNext(Long id, Long limit);
    12. @Query(value = "SELECT * FROM resident AS r WHERE r.id < ?1 ORDER BY r.id DESC LIMIT ?2",
    13. nativeQuery = true)
    14. List fetchAllAscPrevious(Long id, Long limit);
    15. @Query(value = "SELECT count(*) FROM resident", nativeQuery = true)
    16. public Long fetchCount();
    17. @Query(value = "SELECT min(id) FROM resident", nativeQuery = true)
    18. public Long fetchMinId();
    19. @Query(value = "SELECT max(id) FROM resident", nativeQuery = true)
    20. public Long fetchMaxId();
    21. }

    控制器

    1. package com.springboot.thymeleaf.pagination.v2.controller;
    2. import com.springboot.thymeleaf.pagination.v2.model.Resident;
    3. import com.springboot.thymeleaf.pagination.v2.repository.ResidentRepository;
    4. import com.springboot.thymeleaf.pagination.v2.service.ResidentService;
    5. import java.util.Collections;
    6. import lombok.extern.slf4j.Slf4j;
    7. import org.springframework.beans.factory.annotation.Autowired;
    8. import org.springframework.stereotype.Controller;
    9. import org.springframework.ui.Model;
    10. import org.springframework.web.bind.annotation.GetMapping;
    11. import java.util.List;
    12. import org.springframework.web.bind.annotation.RequestParam;
    13. // Causes Lombok to generate a logger field.
    14. @Slf4j
    15. @Controller
    16. public class ResidentController {
    17. private static final int DEFAULT_PAGE_NUMBER = 1;
    18. private static final int DEFAULT_PAGE_SIZE = 10;
    19. @Autowired
    20. private ResidentService service;
    21. @Autowired
    22. private ResidentRepository repository;
    23. @GetMapping(value = "/")
    24. public String viewIndexPage() {
    25. log.info("Redirecting the index page to the controller method for fetching the residents in a paginated fashion.");
    26. return "redirect:residents/paginated/" + DEFAULT_PAGE_NUMBER + "/" + DEFAULT_PAGE_SIZE;
    27. }
    28. @GetMapping("/residents")
    29. public String getPaginatedResidents(Model model, @RequestParam(required = false) String keyword, @RequestParam(defaultValue = "next") String dir,
    30. @RequestParam(defaultValue = "0") Long page,
    31. @RequestParam(defaultValue = "10") Long size) {
    32. log.info("Getting the residents in a paginated way for page-number = {} and page-size = {}.", page, size);
    33. if (dir.equals("next")) {
    34. List fetchAllAscNext = repository.fetchAllAscNext(page, size);
    35. model.addAttribute("responseEntity", fetchAllAscNext);
    36. model.addAttribute("max", fetchAllAscNext.get(fetchAllAscNext.size() - 1).getId());
    37. model.addAttribute("min", fetchAllAscNext.get(0).getId());
    38. } else {
    39. List fetchAllAscPrevious = repository.fetchAllAscPrevious(page, size);
    40. Collections.reverse(fetchAllAscPrevious);
    41. model.addAttribute("responseEntity", fetchAllAscPrevious);
    42. model.addAttribute("max", fetchAllAscPrevious.get(fetchAllAscPrevious.size() - 1).getId());
    43. model.addAttribute("min", fetchAllAscPrevious.get(0).getId());
    44. }
    45. model.addAttribute("fetchCount", repository.fetchCount());
    46. model.addAttribute("fetchMinId", repository.fetchMinId());
    47. model.addAttribute("fetchMaxId", repository.fetchMaxId());
    48. return "index";
    49. }
    50. }

    视图

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Index pagetitle>
    6. <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
    7. <style type="text/css">
    8. th {
    9. text-align: center;
    10. font-weight: bold;
    11. border-top: none !important;
    12. }
    13. th, td {
    14. white-space: nowrap;
    15. }
    16. .mt-20 {
    17. margin-top: 20px;
    18. }
    19. .table-alignment {
    20. margin-left: -200px;
    21. }
    22. style>
    23. head>
    24. <body>
    25. <div class="container">
    26. <h3 class="text-info text-center mt-20">Pagination Example : Residentsh3>
    27. <table class="table table-striped table-alignment mt-20 text-center">
    28. <thead id="residentsTable">
    29. <tr>
    30. <th>Idth>
    31. <th>Full nameth>
    32. <th>Ageth>
    33. <th>Genderth>
    34. <th>Phone Numberth>
    35. <th>Email Addressth>
    36. <th>Date of Birthth>
    37. <th>Home Addressth>
    38. <th>Nationalityth>
    39. <th>First Languageth>
    40. tr>
    41. thead>
    42. <tbody>
    43. <tr th:each="resident : ${responseEntity}">
    44. <td th:text="${resident.id}">td>
    45. <td th:text="${resident.fullName}">td>
    46. <td th:text="${resident.age}">td>
    47. <td th:text="${resident.gender}">td>
    48. <td th:text="${resident.phoneNumber}">td>
    49. <td th:text="${resident.emailAddress}">td>
    50. <td th:text="${resident.dateOfBirth}">td>
    51. <td th:text="${resident.homeAddress}">td>
    52. <td th:text="${resident.nationality}">td>
    53. <td th:text="${resident.firstLanguage}">td>
    54. tr>
    55. tbody>
    56. table>
    57. <div class="row">
    58. <div>
    59. <div>
    60. Total Items: [[${fetchCount}]]
    61. div>
    62. <div>
    63. <a th:if="${min > fetchMinId}"
    64. th:href="@{'/residents/?page='+${min}+'&size=10&dir=prev'}" >
    65. Prev
    66. a>
    67. <span th:unless="${min > fetchMinId}">Prevspan>
    68. div>
    69. <div>
    70. <a th:if="${max < fetchMaxId}"
    71. th:href="@{'/residents/?page='+${max}+'&size=10&dir=next'}" >
    72. Next
    73. a>
    74. <span th:unless="${max < fetchMaxId}">Nextspan>
    75. div>
    76. div>
    77. div>
    78. div>
    79. body>
    80. html>

  • 相关阅读:
    spring的简单使用(配合Druid操作数据库)
    JVM性能调优
    C语言中的函数(超详细)
    WPF开发随笔收录-WriteableBitmap绘制高性能曲线图
    Linux Day18 TCP_UDP协议及相关知识
    Qt Design Studio 4.5现已发布
    电容笔有什么用?Ipad2018电容笔推荐
    go 类型
    Python每日一练 05
    四种垃圾回收算法
  • 原文地址:https://blog.csdn.net/allway2/article/details/128196551