在本文中,我将解释 如何使用启用分页的 API 以及排序和过滤来实现 Spring Boot 项目。在此实际应用程序开发中,我在 Spring Data Core 中使用 Pageable,Spring Data JPA 和基于 MySQL 的数据库,您可以将其与 MongoDB 或您想要的任何其他数据库一起使用。
对于本教程,我将使用我为之开发的库 REST API,
如果你真的是 Spring boot 和 REST API 开发的新手,最好阅读上面的教程,或者直接从GitHub下载共享代码。
将使用的技术,
- Java 1.8
- Spring Boot 2.3.4 发布
- JPA
- MySQL
- 龙目岛
- 摇篮
- IDE 的 IntelliJ 理念
什么是分页、排序和过滤
假设我们的数据库中有大量数据,例如:亚马逊的图书列表。那么我们如何在网页上展示这些书籍呢?
有两种方法可以在网页上显示这些书籍。第一个是在一个网页中一次性显示所有书籍,这可能会花费更多内存,而对于像亚马逊这样的书籍数据库来说,这是无法做到的。
但另一种方法是按给定大小从总书籍中划分集合,并在网页上显示选定的集合。此外,在这里,用户有机会选择他需要查看的任何集合,例如打开书中的特定页面。这就是pagination发生的事情。
在Sorting中,我们可以确定应该如何对分页集进行排序,假设您需要按 ISBN Number(国际标准图书编号)对整个图书列表进行排序,您可以在 Spring Boot 中使用 sort 并获得排序和分页的响应。
过滤用于从整个数据集中过滤掉用户选择的数据集。假设我们正在按最终用户的给定名称按名称过滤书籍列表。我们可以使用过滤来做到这一点。
它如何与 API 一起工作?
分页 API 请求
所以正如我上面解释的,我们可以使用对 API 有特殊请求的分页,包括页码、页面大小和排序。因此,如果您不这样做,基本上您可以将这些元素与您的请求一起传递,您的 API 能够为这些元素设置默认值并发送分页响应。
http://localhost:8081/api/library/book/search?page=0&size=10&sort=isbn
在这里,我们将页码设置为 0,这是数据集中的第一页,每个响应的大小为 10 本书,并按 ISBN 号对这些书进行排序。
分页 API 响应
在这里,我们可以返回为用户请求检索的任何数据集。但是当我们使用分页时,我们可以发送更多细节以及来自数据库的数据集,它是可选的,但很好。
这些是结果集中的项目数和总页数,当我们使用这些分页 API 并构建像数据表这样的前端 UI 组件时,这些值将可用。
{
"bookList": [
{
"id": 4,
"name": "Specification by Example",
"isbn": "1617290084",
"imageUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
"author": {
"id": 4,
"firstName": "Gojko",
"lastName": "Adzic"
}
}
],
"numberOfItems": 1,
"numberOfPages": 1
}
这里 bookList 包括给定分页请求下的所有书籍。此外,响应包括项目总数和单独参数中的总页数。
开发 API 端点
正如我在开头提到的,这里我使用Spring Data core 中的 Pageable 和 JPA来实现本教程。此外,上述库已经添加到代码库中。所以你不需要在项目中添加额外的依赖。
在 Spring Boot 中实现启用分页和排序的 API 端点
在这一部分中,我将解释我们如何在 spring boot 项目中使用 pageable 来实现分页和排序。
因此,在这里我将开发单独的搜索端点,以通过分页和排序从数据库中搜索书籍。
首先,我们应该实现分页 API 响应类,以将 API 响应带给 API 消费者。
package com.javatodev.api.model.response;
import com.javatodev.api.model.Book;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class PaginatedBookResponse {
private List<Book> bookList;
private Long numberOfItems;
private int numberOfPages;
}
在这个例子中,我使用Lombok 插件来最小化 java classes 中的代码。如果您不熟悉 Lombok,请阅读我们关于在 Spring Boot中使用 Lombok 指南的文章,我已经解释了我们如何使用这些新的注解,如 @Data 和 @Builder。
然后我们应该实现服务方法以使用存储库从数据库中读取分页数据集并返回为PaginatedBookResponse。
为此,将以下内容添加到 LibraryService.java,
public PaginatedBookResponse readBooks(Pageable pageable) {
Page<Book> books = bookRepository.findAll(pageable);
return PaginatedBookResponse.builder()
.numberOfItems(books.getTotalElements()).numberOfPages(books.getTotalPages())
.bookList(books.getContent())
.build();
}
在这里,我们从 Rest Controller 级别获取 Pageable 请求,并使用它从 Repository 层请求分页数据。
如何在 JpaRepository 中使用可分页?
在这里,我们使用JpaRepository开发了所有存储库,它在内部扩展了 PagingAndSortingRepository,JpaRepository 允许我们使用带有 findAll 方法的 pageable ,而无需执行任何自定义实现。
Page<T> findAll(Pageable pageable);
它以 Page<T> 响应,其中包括我们需要在 API 中拥有的所有值。
所以我们可以将这些值绑定到我们之前开发的响应类,如下所示。
PaginatedBookResponse.builder() .numberOfItems(books.getTotalElements())
.numberOfPages(books.getTotalPages())
.bookList(books.getContent())
.build();
实现 API 端点以接受分页请求
现在我们有了应用程序中必须具备的服务实现。现在我们可以设置接受分页请求的 API 端点。
只需将以下 API 端点添加到 LibraryController.java。
@GetMapping("/book/search")
public ResponseEntity readBooks (Pageable pageable) {
return ResponseEntity.ok(libraryService.readBooks(pageable));
}
而 Spring Boot 最棒的地方在于,它具有将分页请求直接接受到可分页对象的能力。所以我们只需要将它传递到服务和存储库中。
现在我们的 API 完成了分页和排序,
使用过滤实现 API 端点
在这里,我们接受来自请求的自定义查询并向 API 添加过滤机制。
在这里,我将使用单独的 API 端点来演示它,但您可以使用单个 API 端点来支持分页、过滤和排序。
首先,将以下方法添加到 BookRepository.java 中,该方法允许按名称阅读书籍以及分页请求数据。在这里,我将阅读名称中包含用户输入查询的每一本书,
Page<Book> findAllByNameContains(String name, Pageable pageable);
然后实现服务代码以支持过滤,在 LibraryService.java 中添加以下方法
public PaginatedBookResponse filterBooks(String name, Pageable pageable) {
Page<Book> books = bookRepository.findAllByNameContains(name, pageable);
return PaginatedBookResponse.builder()
.numberOfItems(books.getTotalElements()).numberOfPages(books.getTotalPages())
.bookList(books.getContent())
.build();
}
之后,设置 API 端点以方便必要的实施,
@GetMapping("/book/search/filter")
public ResponseEntity readBooksWithFilter (@RequestParam("query") String query, Pageable pageable) {
return ResponseEntity.ok(libraryService.filterBooks(query, pageable));
}
全部完成,让我们测试我们的 API,
测试 API
- 分页请求
不绑定大小和页面等任何参数,在这里它将获取默认值并从API返回必要的数据
http://localhost:8081/api/library/book/search
带有必要参数的分页请求。
http://localhost:8081/api/library/book/search?page=0&size=10
- 带排序的分页请求
http://localhost:8081/api/library/book/search?page=0&size=10&sort=isbn
改变排序方向,默认按ASC顺序排序,你可以按如下方式将其更改为DESC,
http://localhost:8081/api/library/book/search?page=0&size=10&sort=id,DESC
添加多个排序参数,
http://localhost:8081/api/library/book/search?page=0&size=10&sort=id,isbn
这里 API 将根据 id 对项目进行排序,然后使用 isbn 再次对结果进行排序。
3. 带过滤的分页请求
http://localhost:8081/api/library/book/search/filter?query=fil&page=0&size=10
结论
一切都完成了,现在我希望你对如何使用 Spring Boot 以及排序和过滤构建启用分页的 rest API 有一个很好的理解。评论您在开发 Spring Boot API 时遇到的想法或问题。
您可以从我们的Github找到本教程的源代码 。
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bezkoder</groupId>
<artifactId>spring-boot-mysql-pagination-filtering-sorting</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-mysql-pagination-filtering-sorting</name>
<description>Spring Boot Data JPA: Paging and Sorting example Rest Apis</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>