在上一篇文章中,我们已经知道如何使用 Spring Data JPA 构建 Spring Boot Rest CRUD APIs。在本教程中,我将继续使用 Spring Data JPA 和Pageable制作服务器端分页和过滤器。
使网站友好的最重要的事情之一是响应时间,而分页就是这个原因。例如,这个 bezkoder.com 网站有数百个教程,我们不想一次看到所有教程。分页是指以一页为单位显示全部的一小部分。
假设我们在数据库中有tutorials表,如下所示:
以下是一些用于分页的 url 示例(带/不带过滤器):
/api/tutorials?page=1&size=5
/api/tutorials?size=5
: 使用页面的默认值/api/tutorials?title=data&page=1&size=3
:按包含“数据”的标题进行分页和过滤/api/tutorials/published?page=2
:按“已发布”状态进行分页和过滤这是我们希望从 API 获得的服务器端分页结果的结构:
{
"totalItems": 8,
"tutorials": [...],
"totalPages": 3,
"currentPage": 1
}
阅读具有默认页面索引 (0) 和页面大小 (3) 的教程:
指示页面索引 = 2,但未指定总共 8 个项目的大小(默认值:3):
指示 size = 5 但不指定页面索引(默认值:0):
对于页面索引 = 1 和页面大小 = 5(总共 8 项):
按包含字符串的标题进行分页和过滤:
按发布状态分页和过滤:
为了帮助我们处理这种情况,Spring Data JPA 提供了使用PagingAndSortingRepository实现分页的方法。
PagingAndSortingRepository
扩展CrudRepository以提供额外的方法来使用分页抽象检索实体。
public interface PagingAndSortingRepository extends CrudRepository {
Page findAll(Pageable pageable);
}
findAll(Pageable pageable)
:返回Page
满足对象提供的分页条件的实体Pageable
。
Spring Data 还支持从方法名称创建许多有用的查询,我们将在此示例中使用这些名称来过滤结果,例如:
Page findByPublished(boolean published, Pageable pageable);
Page findByTitleContaining(String title, Pageable pageable);
您可以在此处的方法名称中找到更多受支持的关键字。
要使用分页对多个字段进行排序,请访问教程:
Spring Data JPA 按多列排序/排序 | 弹簧靴
让我们看一下Page对象。
Page
是Slice
带有几个附加方法的子接口。它包含整个列表的元素总数和总页数。
public interface Page extends Slice {
static Page empty();
static Page empty(Pageable pageable);
long getTotalElements();
int getTotalPages();
Page map(Function super T,? extends U> converter);
}
如果项目数量增加,性能可能会受到影响,是时候考虑Slice了。
一个Slice
对象比 a 知道的信息少Page
,例如,下一个或前一个是否可用,或者这个切片是第一个/最后一个。当您不需要项目总数和总页数时,您可以使用它。
public interface Slice extends Streamable {
int getNumber();
int getSize();
int getNumberOfElements();
List getContent();
boolean hasContent();
Sort getSort();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
...
}
现在我们将在上面的 Repository 方法中看到Pageable参数。Spring Data 基础设施将自动识别此参数以将分页和排序应用于数据库。
该Pageable
界面包含有关所请求页面的信息,例如页面的大小和数量。
public interface Pageable {
int getPageNumber();
int getPageSize();
long getOffset();
Sort getSort();
Pageable next();
Pageable previousOrFirst();
Pageable first();
boolean hasPrevious();
...
}
所以当我们想在结果中获得分页(有或没有过滤器)时,我们只需添加Pageable
到方法的定义中作为参数。
Page findAll(Pageable pageable);
Page findByPublished(boolean published, Pageable pageable);
Page findByTitleContaining(String title, Pageable pageable);
这就是我们使用实现接口的PageRequestPageable
类创建对象的方式:Pageable
Pageable paging = PageRequest.of(page, size);
page
:从零开始的页面索引,不得为负数。size
:要返回的页面中的项目数,必须大于0。你可以一步一步来,或者在这篇文章中获取源代码:
Spring Boot, Spring Data JPA – Rest CRUD API example
Spring 项目包含我们只需要添加一些更改以使分页正常工作的结构。
或者您可以在本教程的最后获取新的 Github 源代码(包括分页和排序)。
我们有这样的教程实体:
package com.bezkoder.spring.data.jpa.pagingsorting.model;
import javax.persistence.*;
@Entity
@Table(name = "tutorials")
public class Tutorial {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@Column(name = "published")
private boolean published;
public Tutorial() {
}
public Tutorial(String title, String description, boolean published) {
this.title = title;
this.description = description;
this.published = published;
}
public long getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isPublished() {
return published;
}
public void setPublished(boolean isPublished) {
this.published = isPublished;
}
@Override
public String toString() {
return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
}
}
在本教程的早期,我们知道PagingAndSortingRepository
,但在本示例中,为了保持连续性并利用 Spring Data JPA,我们继续使用扩展接口的JpaRepository 。PagingAndSortingRepository
package com.bezkoder.spring.data.jpa.pagingsorting.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;
public interface TutorialRepository extends JpaRepository {
Page findByPublished(boolean published, Pageable pageable);
Page findByTitleContaining(String title, Pageable pageable);
}
pageable
在上面的代码中,我们使用带有 Spring Query Creation的add参数来查找所有标题包含输入字符串的教程。
更多派生查询:
Spring Boot 中的 JPA 存储库查询示例
带@Query
注释的自定义查询:
Spring JPA @Query 示例:Spring Boot 中的自定义查询
通常,在 HTTP 请求 URL 中,分页参数是可选的。因此,如果我们的 Rest API 支持服务器端分页,我们应该提供默认值以使分页工作,即使客户端没有指定这些参数。
package com.bezkoder.spring.data.jpa.pagingsorting.controller;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
...
@RestController
@RequestMapping("/api")
public class TutorialController {
@Autowired
TutorialRepository tutorialRepository;
@GetMapping("/tutorials")
public ResponseEntity
@RequestParam
在上面的代码中,我们使用注释来接受分页参数page
, size
。默认情况下,3
教程将从页面索引中的数据库中获取0
。
接下来,我们用&创建一个Pageable
对象。然后检查参数是否存在。page
size
title
findAll(paging)
,分页就是Pageable
上面的对象。title
使用findByTitleContaining(title, paging)
。两种方法都返回一个Page
对象。我们称之为:
getContent()
检索页面中的项目列表。getNumber()
当前页面。getTotalElements()
对于存储在数据库中的总项目。getTotalPages()
总页数。在这篇文章中,我们学习了如何使用 Spring Data JPA、Page 和 Pageable 接口在 Spring Boot 应用程序中创建分页和过滤结果。
我们还看到它JpaRepository
支持一种无需样板代码即可制作服务器端分页和过滤方法的好方法。
您可以在Github上找到本教程的完整源代码。