Spring Data JPA 按多个列排序

本文介绍了如何在SpringBoot应用中使用SpringDataJPA进行多列排序,并结合分页功能。实例展示了如何按指定列和方向创建Sort对象,以及在Controller中处理排序参数,实现分页教程列表的API设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在本教程中,我将向您展示如何使用Spring Data JPA在Spring Boot中按多个列对结果进行排序/排序。并且介绍同时应用排序和分页的方法。

Spring 数据排序多列示例概述

假设我们在数据库中有教程表,如下所示:

以下是一些按单列/多列(带/不带分页)排序的 URL 示例,按升序或降序排序:

  • /api/tutorials
    按 [id, 降序] 排序(默认)
  • /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, 降序] 的教程:

– 获取所有教程,按单列排序 [标题,升序]:

– 获取所有教程,按多列排序 [已发布,降序] & [标题,升序]:

使用弹簧数据JPA按多个列排序

为了帮助我们处理这种情况,Spring Data JPA 提供了使用分页和排序存储库实现分页的方法。

PagingAndSortingRepository扩展 Crud存储库以提供使用排序抽象检索实体的其他方法。因此,您可以向查询方法添加一个特殊的 Sort 参数。

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
  Iterable<T> findAll(Sort sort);
}

findAll(Sort sort):返回满足对象提供的排序条件Sort的实体的Iterable

您还可以使用Sort其他参数定义更多派生查询方法和自定义查询方法。例如,以下方法返回标题包含给定字符串的教程列表:

List<Tutorial> findByTitleContaining(String title, Sort sort);

您可以在此处找到方法名称中更多受支持的关键字。

让我们继续探索Sort类。

弹簧数据排序和排序

Sort 类为数据库查询提供排序选项,在选择单/多排序列和方向(升序/降序)时具有更大的灵活性。

例如,我们使用 by()descending() 、​​​​​​​​​​​​​​and()方法来创建对象并将其传递给SortRepository.findAll() ​​​​​​​:

// order by 'published' column - ascending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published"));

// order by 'published' column, descending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published").descending());

// order by 'published' column - descending, then order by 'title' - ascending
List<Tutorial> tutorials =
     tutorialRepository.findAll(Sort.by("published").descending().and(Sort.by("title")));

我们还可以使用Order对象列表创建一个新Sort对象​​​​​​​

List<Order> orders = new ArrayList<Order>();

Order order1 = new Order(Sort.Direction.DESC, "published");
orders.add(order1);

Order order2 = new Order(Sort.Direction.ASC, "title");
orders.add(order2);

List<Tutorial> tutorials = tutorialRepository.findAll(Sort.by(orders));

分页和排序

如果我们想要对数据进行排序和分页,该怎么办?

CrudRepository还提供了使用分页抽象检索实体的其他方法。

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
  Page<T> findAll(Pageable pageable);
}

findAll(Pageable pageable):返回满足​​​​​​​Pageable对象提供的分页条件的Page实体。

Spring Data还支持从方法名称创建许多有用的查询,我们将在此示例中使用这些方法名称来过滤结果,例如:

Page<Tutorial> findByPublished(boolean published, Pageable pageable);
Page<Tutorial> 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<Tutorial, Long> {
  Page<Tutorial> findByPublished(boolean published, Pageable pageable);

  Page<Tutorial> findByTitleContaining(String title, Pageable pageable);
  
  List<Tutorial> 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.DESSort.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<List<Tutorial>> getAllTutorials(@RequestParam(defaultValue = "id,desc") String[] sort) {

    try {
      List<Order> orders = new ArrayList<Order>();

      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<Tutorial> 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 回收的弹簧启动单元测试
– 静止控制器的弹簧启动单元测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值