在本教程中,我将向您展示如何使用Spring Data JPA在Spring Boot中按多个列对结果进行排序/排序。并且介绍同时应用排序和分页的方法。
假设我们在数据库中有教程表,如下所示:
以下是一些按单列/多列(带/不带分页)排序的 URL 示例,按升序或降序排序:
/api/tutorials
/api/tutorials?sort=title,asc
/api/tutorials?sort=published,desc&sort=title,asc
/api/tutorials?page=0&size=3&sort=published,desc&sort=title,asc
在本教程中,为了帮助您清楚地了解如何使用Spring Boot进行排序,我将创建具有不同响应结构的分离端点:
/api/sortedtutorials
- [
- {
- "id": 8,
- "title": "Spring Data JPA Tut#8",
- "description": "Tut#8 Description",
- "published": true
- },
- ...
- ...
- ...
- {
- "id": 1,
- "title": "Spring Boot Tut#1",
- "description": "Tut#1 Description",
- "published": false
- }
- ]
/api/tutorials
- {
- "totalItems": 8,
- "tutorials": [
- ...
- ],
- "totalPages": 3,
- "currentPage": 1
- }
请访问: 春靴分页和排序示例
让我们看一下构建此弹簧启动应用程序后的结果:
– 获取所有具有默认顺序 [id, 降序] 的教程:
– 获取所有教程,按单列排序 [标题,升序]:
– 获取所有教程,按多列排序 [已发布,降序] & [标题,升序]:
为了帮助我们处理这种情况,Spring Data JPA 提供了使用分页和排序存储库实现分页的方法。
PagingAndSortingRepository
扩展 Crud存储库以提供使用排序抽象检索实体的其他方法。因此,您可以向查询方法添加一个特殊的 Sort 参数。
- public interface PagingAndSortingRepository
extends CrudRepository { - Iterable
findAll(Sort sort); - }
findAll(Sort sort)
:返回满足对象提供的排序条件Sort
的实体的Iterable
。
您还可以使用Sort
其他参数定义更多派生查询方法和自定义查询方法。例如,以下方法返回标题包含给定字符串的教程列表:
List findByTitleContaining(String title, Sort sort);
您可以在此处找到方法名称中更多受支持的关键字。
让我们继续探索Sort
类。
Sort 类为数据库查询提供排序选项,在选择单/多排序列和方向(升序/降序)时具有更大的灵活性。
例如,我们使用 by()
、descending()
、and()
方法来创建对象并将其传递给Sort
Repository.findAll()
:
- // order by 'published' column - ascending
- List
tutorials = - tutorialRepository.findAll(Sort.by("published"));
-
- // order by 'published' column, descending
- List
tutorials = - tutorialRepository.findAll(Sort.by("published").descending());
-
- // order by 'published' column - descending, then order by 'title' - ascending
- List
tutorials = - tutorialRepository.findAll(Sort.by("published").descending().and(Sort.by("title")));
我们还可以使用Order对象列表创建一个新Sort
对象
。
- List
orders = new ArrayList(); -
- Order order1 = new Order(Sort.Direction.DESC, "published");
- orders.add(order1);
-
- Order order2 = new Order(Sort.Direction.ASC, "title");
- orders.add(order2);
-
- List
tutorials = tutorialRepository.findAll(Sort.by(orders));
如果我们想要对数据进行排序和分页,该怎么办?
CrudRepository
还提供了使用分页抽象检索实体的其他方法。
- public interface PagingAndSortingRepository
extends CrudRepository { - Page
findAll(Pageable pageable); - }
findAll(Pageable pageable)
:返回满足Pageable
对象提供的分页条件的Page
实体。
Spring Data还支持从方法名称创建许多有用的查询,我们将在此示例中使用这些方法名称来过滤结果,例如:
- Page
findByPublished(boolean published, Pageable pageable); - Page
findByTitleContaining(String title, Pageable pageable);
有关分页和排序的更多详细信息,请访问:
春靴分页和排序示例
您可以逐步进行操作,也可以在本文中获取源代码:
弹簧启动,弹簧数据JPA - Rest CRUD API示例
Spring 项目包含的结构,我们只需要添加一些更改即可使分页正常工作。
或者,您可以在本教程结束时获取新的 Github 源代码(包括分页和排序)。
这是我们将要处理的教程实体:
model/Tutorial.java
- 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数据JPA,我们继续使用扩展PagingAndSortingRepository
接口的Jpa存储库。
repository/TutorialRepository.java
- package com.bezkoder.spring.data.jpa.pagingsorting.repository;
-
- import java.util.List;
-
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.domain.Sort;
- 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); -
- List
findByTitleContaining(String title, Sort sort); - }
在上面的代码中,我们将添加pageable
参数与Spring查询创建一起使用,以查找标题包含输入字符串的所有教程。
更多派生查询,请参见:
弹簧启动中的 JPA 存储库查询示例
带注释的自定义查询:
春季 JPA @Query示例:春季启动中的自定义查询@Query
要获取多个排序请求参数,我们使用默认参数defaultValue = "id,desc"的
@RequestParam String[] sort
。
在编写 Controller 方法来处理这种情况之前,让我们看看我们用参数检索了什么:
?sort=column1,direction1
:排序单列String[] sort
是一个包含 2 个元素的数组:[“列 1”、“方向 1”]?sort=column1,direction1&sort=column2,direction2
:对多列进行排序,String[] sort
也是一个包含 2 个元素的数组:[“列 1,方向 1”、“列 2,方向 2”]这就是为什么我们需要检查数组中的第一项是否包含","
。
我们还需要转换/转化"asc"
"desc"
为Sort.Direction.ASC
/Sort.Direction.DES
与Sort.Order类
一起工作。
controller/TutorialController.java
- package com.bezkoder.spring.data.jpa.pagingsorting.controller;
-
- import org.springframework.data.domain.Sort;
- import org.springframework.data.domain.Sort.Order;
- ...
- import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;
- import com.bezkoder.spring.data.jpa.pagingsorting.repository.TutorialRepository;
-
- @RestController
- @RequestMapping("/api")
- public class TutorialController {
-
- @Autowired
- TutorialRepository tutorialRepository;
-
- private Sort.Direction getSortDirection(String direction) {
- if (direction.equals("asc")) {
- return Sort.Direction.ASC;
- } else if (direction.equals("desc")) {
- return Sort.Direction.DESC;
- }
-
- return Sort.Direction.ASC;
- }
-
- @GetMapping("/sortedtutorials")
- public ResponseEntity
> getAllTutorials(@RequestParam(defaultValue = "id,desc") String[] sort) {
-
- try {
- List
orders = new ArrayList(); -
- if (sort[0].contains(",")) {
- // will sort more than 2 columns
- for (String sortOrder : sort) {
- // sortOrder="column, direction"
- String[] _sort = sortOrder.split(",");
- orders.add(new Order(getSortDirection(_sort[1]), _sort[0]));
- }
- } else {
- // sort=[column, direction]
- orders.add(new Order(getSortDirection(sort[1]), sort[0]));
- }
-
- List
tutorials = tutorialRepository.findAll(Sort.by(orders)); -
- if (tutorials.isEmpty()) {
- return new ResponseEntity<>(HttpStatus.NO_CONTENT);
- }
-
- return new ResponseEntity<>(tutorials, HttpStatus.OK);
- } catch (Exception e) {
- return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
- }
- }
-
- }
将分页和排序结合在一起的控制器怎么样?
请访问: 春靴分页和排序示例
在这篇文章中,我们学习了如何使用弹簧数据JPA,排序类和可分页界面在弹簧启动应用程序中按多个列进行排序/排序。
我们还看到,这支持了一种无需样板代码即可制作排序、分页和筛选方法的好方法。JpaRepository
带注释的自定义查询:
春季 JPA @Query示例:春季启动中的自定义查询@Query
您还可以在本文中了解如何:
- 分页和过滤。
– 在这篇文章中处理异常。
– 通过本教程在 AWS 上部署此春季启动应用程序(免费)。
学习愉快!再见。
对于分页和排序:
弹簧靴分页和排序示例
您可以在 Github 上找到本教程的完整源代码。
更多派生查询,请参见:
弹簧启动中的 JPA 存储库查询示例
您可以将代码用作以下帖子的附加功能:
– 弹簧启动,弹簧数据 JPA,H2 示例
– 弹簧启动、弹簧数据 JPA、MySQL 示例
– 弹簧启动、弹簧数据 JPA、PostgreSQL 示例
– 弹簧启动、弹簧数据 JPA、SQL Server 示例
– 弹簧启动、弹簧数据 JPA、Oracle 示例
关联:
– 使用 JPA 的弹簧启动一对一示例,休眠
– 使用 JPA 的弹簧启动一对多示例,使用 JPA 的
弹簧启动多对多示例,休眠
单元测试:
– JPA 回收的弹簧启动单元测试
– 静止控制器的弹簧启动单元测试