• 使用Spring Boot进行分页


    为 Web 应用程序的用户,我们希望页面能够快速加载并且只显示 与我们相关的信息。对于显示项目列表的页面,这意味着 仅显示部分项目,而不是一次显示所有项目

    快速加载第一页后,UI 可以提供筛选器、 排序和分页,帮助用户快速找到他或 她正在寻找。

    在本教程中,我们将检查 Spring Data 的分页支持,并创建如何使用的示例 并对其进行配置以及有关其如何在幕后工作的一些信息。

    示例代码

    本文附有GitHub 上的工作代码示例。

    分页与分页

    术语“分页”和“分页”通常用作同义词。他们的意思并不完全相同, 然而。在查阅了各种网络词典后,我拼凑出了以下定义, 我将在本文中使用:

    页是从数据库中加载一页又一页项目的行为,以便 保护资源。这就是本文大部分内容的内容。

    分页是一个 UI 元素,它提供一系列页码,让用户选择 接下来要加载的页面。

    初始化示例项目

    在本教程中,我们使用 Spring Boot 来引导一个项目。您可以 通过使用Spring Initializr并选择以下依赖项来创建类似的项目:

    • 太平绅士
    • H2
    • 龙目岛

    我还用 JUnit 5 替换了 JUnit 4,以便生成的依赖项 看起来像这样(Gradle 表示法):

    1. dependencies {
    2. implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    3. implementation 'org.springframework.boot:spring-boot-starter-web'
    4. compileOnly 'org.projectlombok:lombok'
    5. annotationProcessor 'org.projectlombok:lombok'
    6. runtimeOnly 'com.h2database:h2'
    7. testImplementation('org.junit.jupiter:junit-jupiter:5.4.0')
    8. testImplementation('org.springframework.boot:spring-boot-starter-test'){
    9. exclude group: 'junit', module: 'junit'
    10. }
    11. }

    春季数据Pageable

    无论我们想做传统的分页,无限滚动还是简单的“上一个” 和“下一个”链接,后端的实现是相同的。

    如果客户端只想显示项目列表的“切片”,则需要提供 描述此切片的一些输入参数。在 Spring 数据中,这些参数捆绑在 界面。它提供了以下方法,其中包括(评论是我的):Pageable

    1. public interface Pageable {
    2. // number of the current page int getPageNumber();
    3. // size of the pages int getPageSize();
    4. // sorting parameters Sort getSort();
    5. // ... more methods }

    每当我们只想加载完整项目列表的一部分时,我们都可以使用 ainstance 作为输入参数,因为它提供 要加载的页面编号以及页面大小。通过课堂, 它还允许定义要排序的字段及其方向 应排序(升序或降序)。PageableSort

    创建实例的最常见方法是使用实现:PageablePageRequest

    1. Pageable pageable = PageRequest.of(0, 5, Sort.by(
    2. Order.asc("name"),
    3. Order.desc("id")));

    这将为第一页创建一个请求,其中首先订购了 5 个项目 按名称(升序),按 ID (降序)。请注意,默认情况下页面索引是从零开始的!

    困惑?java.awt.print.Pageable

    使用时,您会注意到 IDE 有时会 建议进口代替春天的班。由于我们很可能不需要包中的任何类,因此我们可以 告诉我们的 IDE 完全忽略它。Pageablejava.awt.print.PageablePageablejava.awt

    在IntelliJ中,转到设置中的“常规->编辑器->自动导入”,然后添加到标有“从导入和完成中排除”的列表中。java.awt.*

    在 Eclipse 中,转到首选项中的“Java -> 外观 -> 类型过滤器”,然后 添加到包列表中。java.awt.*

    春天的数据沙子PageSlice

    同时捆绑分页请求的输入参数,与接口 为返回给客户端的项目页面提供元数据(评论是我的):PageablePageSlice

    1. public interface Page extends Slice{
    2. // total number of pages int getTotalPages();
    3. // total number of items long getTotalElements();
    4. // ... more methods
    5. }
    1. public interface Slice {
    2. // current page number int getNumber();
    3. // page size int getSize();
    4. // number of items on the current page int getNumberOfElements();
    5. // list of items on this page List getContent();
    6. // ... more methods
    7. }

    通过接口提供的数据,客户端拥有所需的所有信息 以提供分页功能。Page

    我们可以改用接口,如果我们不这样做 需要项目或页面的总数,例如,如果我们只想提供 “上一页”和“下一页”按钮,不需要“第一页”和“最后一页” 按钮。Slice

    接口最常见的实现由类提供:PagePageImpl

    1. Pageable pageable = ...;
    2. List listOfCharacters = ...;
    3. long totalCharacters = 100;
    4. Page page =
    5. new PageImpl<>(listOfCharacters, pageable, totalCharacters);

    Web 控制器中的分页

    如果我们想在 Web 控制器中返回一个(或)项,它需要接受 定义分页参数的参数,将其传递给数据库, ,然后将 aobject 返回给客户端。PageSlicePageablePage

    激活弹簧数据网络支持

    分页必须由底层持久性层支持,以便 为任何查询提供分页答案。这就是为什么分页页面类源自 Spring 数据模块,而不是像人们可能的那样。 可疑,来自Spring Web模块。

    在启用了自动配置(这是默认设置)的 Spring 启动应用程序中,我们没有 做任何事情,因为它将加载默认情况下,这 包括加载必要 Bean 的注释。SpringDataWebAutoConfiguration@EnableSpringDataWebSupport

    在没有 Spring Boot 的普通 Spring 应用程序中,我们必须自己在类上使用:@EnableSpringDataWebSupport@Configuration

    1. @Configuration
    2. @EnableSpringDataWebSupport
    3. class PaginationConfiguration {
    4. }

    如果我们在 Web 控制器方法中使用或参数而没有 激活了 Spring 数据 Web 支持,我们将得到如下异常:PageableSort

    1. java.lang.NoSuchMethodException: org.springframework.data.domain.Pageable.()
    2. java.lang.NoSuchMethodException: org.springframework.data.domain.Sort.()

    这些异常意味着 Spring 尝试创建主动脉实例 并且失败,因为它们没有默认构造函数。PageableSort

    Spring Data Web 支持修复了这个问题,因为它将PageableHandlerMethodArgumentResolver 和 SortHandlerMethodArgumentResolverbean 添加到 应用程序上下文,负责查找 Web 控制器方法参数 类型并且页面大小排序查询参数的值填充它们PageableSort

    接受参数Pageable

    启用 Spring 数据网络支持后,我们可以简单地使用 aas 作为输入参数 到 Web 控制器方法并将 Aobject 返回给客户端:PageablePage

    1. @RestController
    2. @RequiredArgsConstructor
    3. class PagedController {
    4. private final MovieCharacterRepository characterRepository;
    5. @GetMapping(path = "/characters/page")
    6. Page loadCharactersPage(Pageable pageable) {
    7. return characterRepository.findAllPage(pageable);
    8. }
    9. }

    集成测试显示,查询参数,和现在已计算 并“注入”到我们的 Web 控制器方法的参数中:pagesizesortPageable

    1. @WebMvcTest(controllers = PagedController.class)
    2. class PagedControllerTest {
    3. @MockBean
    4. private MovieCharacterRepository characterRepository;
    5. @Autowired
    6. private MockMvc mockMvc;
    7. @Test
    8. void evaluatesPageableParameter() throws Exception {
    9. mockMvc.perform(get("/characters/page")
    10. .param("page", "5")
    11. .param("size", "10")
    12. .param("sort", "id,desc") // <-- no space after comma! .param("sort", "name,asc")) // <-- no space after comma! .andExpect(status().isOk());
    13. ArgumentCaptor pageableCaptor =
    14. ArgumentCaptor.forClass(Pageable.class);
    15. verify(characterRepository).findAllPage(pageableCaptor.capture());
    16. PageRequest pageable = (PageRequest) pageableCaptor.getValue();
    17. assertThat(pageable).hasPageNumber(5);
    18. assertThat(pageable).hasPageSize(10);
    19. assertThat(pageable).hasSort("name", Sort.Direction.ASC);
    20. assertThat(pageable).hasSort("id", Sort.Direction.DESC);
    21. }
    22. }

    测试捕获传递到存储库方法的参数并验证 它具有查询参数定义的属性。Pageable

    请注意,我使用了自定义 AssertJ断言,用于在实例上创建可读断言。Pageable

    另请注意,为了按多个字段排序,我们必须提供查询参数 多次。每个字段可以仅包含一个字段名称,假定升序, 或带有顺序的字段名称,用逗号分隔,不带空格。如果有空间 在字段名称和订单之间,不会评估订单sort

    接受参数Sort

    同样,我们可以在 Web 控制器方法中使用独立参数:Sort

    1. @RestController
    2. @RequiredArgsConstructor
    3. class PagedController {
    4. private final MovieCharacterRepository characterRepository;
    5. @GetMapping(path = "/characters/sorted")
    6. List loadCharactersSorted(Sort sort) {
    7. return characterRepository.findAllSorted(sort);
    8. }
    9. }

    当然,对象仅使用查询参数的值填充, 如此测试所示:Sortsort

    1. @WebMvcTest(controllers = PagedController.class)
    2. class PagedControllerTest {
    3. @MockBean
    4. private MovieCharacterRepository characterRepository;
    5. @Autowired
    6. private MockMvc mockMvc;
    7. @Test
    8. void evaluatesSortParameter() throws Exception {
    9. mockMvc.perform(get("/characters/sorted")
    10. .param("sort", "id,desc") // <-- no space after comma!!! .param("sort", "name,asc")) // <-- no space after comma!!! .andExpect(status().isOk());
    11. ArgumentCaptor sortCaptor = ArgumentCaptor.forClass(Sort.class);
    12. verify(characterRepository).findAllSorted(sortCaptor.capture());
    13. Sort sort = sortCaptor.getValue();
    14. assertThat(sort).hasSort("name", Sort.Direction.ASC);
    15. assertThat(sort).hasSort("id", Sort.Direction.DESC);
    16. }
    17. }

    自定义全局分页默认值

    如果我们在调用 带有参数的控制器方法,它将填充 默认值。pagesizesortPageable

    Spring Boot 使用@ConfigurationProperties功能来 将以下属性绑定到类型的 Bean:SpringDataWebProperties

    1. spring.data.web.pageable.size-parameter=size
    2. spring.data.web.pageable.page-parameter=page
    3. spring.data.web.pageable.default-page-size=20
    4. spring.data.web.pageable.one-indexed-parameters=false
    5. spring.data.web.pageable.max-page-size=2000
    6. spring.data.web.pageable.prefix=
    7. spring.data.web.pageable.qualifier-delimiter=_

    以上值是默认值。 其中一些属性不是不言自明的,因此以下是它们的作用:

    • 我们可以更改查询参数的名称size-parametersize
    • 我们可以更改查询参数的名称page-parameterpage
    • 如果没有给出值,我们可以定义参数的默认值default-page-sizesize
    • 我们可以选择参数是以 0 开头还是以 1 开头one-indexed-parameterspage
    • 我们可以选择查询参数允许的最大值(大于此值的值将减少)max-page-sizesize
    • 我们可以为AndQuery参数名称定义一个前缀(而不是参数!prefixpagesizesort

    物业是一个非常特殊的情况。我们可以在 aMethod 参数,用于为分页查询参数提供本地前缀:qualifier-delimiter@QualifierPageable

    1. @RestController
    2. class PagedController {
    3. @GetMapping(path = "/characters/qualifier")
    4. Page loadCharactersPageWithQualifier(
    5. @Qualifier("my") Pageable pageable) {
    6. ...
    7. }
    8. }

    这与上面的属性具有类似的效果,但它也适用于参数。用于分隔前缀 参数名称。在上面的示例中,仅计算查询参数。prefixsortqualifier-delimitermy_pagemy_sizemy_sort

    spring.data.web.*属性未评估?

    如果对上述配置属性的更改不起作用,则 bean 可能未加载到应用程序上下文中。SpringDataWebProperties

    其中一个原因可能是您已经激活了分页支持。这将覆盖, 其中创造了沂豆。仅在普通弹簧应用中使用。@EnableSpringDataWebSupportSpringDataWebAutoConfigurationSpringDataWebProperties@EnableSpringDataWebSupport

    自定义本地寻呼默认值

    有时我们可能只想为单个控制器方法定义默认分页参数。 对于这种情况,我们可以使用theandannotations:@PagableDefault@SortDefault

    1. @RestController
    2. class PagedController {
    3. @GetMapping(path = "/characters/page")
    4. Page loadCharactersPage(
    5. @PageableDefault(page = 0, size = 20)
    6. @SortDefault.SortDefaults({
    7. @SortDefault(sort = "name", direction = Sort.Direction.DESC),
    8. @SortDefault(sort = "id", direction = Sort.Direction.ASC)
    9. }) Pageable pageable) {
    10. ...
    11. }
    12. }

    如果未给出查询参数,则对象现在将填充 批注中定义的默认值。Pageable

    请注意,theannotation 也有属性,但如果我们想要 要定义多个字段以按不同方向排序,我们必须使用。@PageableDefaultsort@SortDefault

    Spring 数据存储库中的分页

    由于本文中描述的分页功能来自Spring Data, Spring Data完全支持分页也就不足为奇了。然而,这种支持是 解释得非常快,因为我们只需要添加正确的参数并返回值 到我们的存储库界面。

    传递分页参数

    我们可以简单地将主动脉实例传递到任何 Spring 数据存储库方法中:PageableSort

    1. interface MovieCharacterRepository
    2. extends CrudRepository {
    3. List findByMovie(String movieName, Pageable pageable);
    4. @Query("select c from MovieCharacter c where c.movie = :movie")
    5. List findByMovieCustom(
    6. @Param("movie") String movieName, Pageable pageable);
    7. @Query("select c from MovieCharacter c where c.movie = :movie")
    8. List findByMovieSorted(
    9. @Param("movie") String movieName, Sort sort);
    10. }

    即使Spring Data提供了一个PagingAndSortingRepository,我们也不必 使用它来获取分页支持。它只是 提供两种方便的方法,一种使用 a,另一种使用 a参数。findAllSortPageable

    返回页面元数据

    如果我们想将页面信息返回给客户端而不是简单的列表, 我们只是让我们的存储库方法简单地返回 aor a:SlicePage

    1. interface MovieCharacterRepository
    2. extends CrudRepository {
    3. Page findByMovie(String movieName, Pageable pageable);
    4. @Query("select c from MovieCharacter c where c.movie = :movie")
    5. Slice findByMovieCustom(
    6. @Param("movie") String movieName, Pageable pageable);
    7. }

    每个返回主动脉的方法都必须只有一个参数,否则 Spring Data将在启动时投诉,但有例外。SlicePagePageable

    结论

    Spring 数据 Web 支持使普通 Spring 应用程序和 Spring 中的分页变得容易。 启动应用程序。这是激活它然后使用正确的输入和输出的问题 控制器和存储库方法中的参数。

    借助 Spring Boot 的配置属性,我们可以对默认值进行细粒度控制。 和参数名称。

    不过,有一些潜在的问题,其中一些我在上面的文字中已经描述了,所以 你不必绊倒它们。

    如果您缺少有关与 Spring 进行寻呼的任何内容,请在此 教程,在评论中让我知道。

    您可以在github 上找到本文中使用的示例代码。

  • 相关阅读:
    Django框架之python后端框架介绍
    AI低代码维格云甘特视图怎么用?
    toString和valueOf
    Android FileProvider笔记
    如何使用OpenCV作图像或矩阵的逻辑运算
    『现学现忘』Docker基础 — 37、ONBUILD指令介绍
    重装系统全流程
    Perforce P4 error: Unable to determine client host name
    生成树协议 STP(spanning-tree protocol)
    腾讯云2023年双十一优惠活动整理汇总
  • 原文地址:https://blog.csdn.net/allway2/article/details/128144945