• Spring Data JPA 按多个列排序


    在本教程中,我将向您展示如何使用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

    1. [
    2. {
    3. "id": 8,
    4. "title": "Spring Data JPA Tut#8",
    5. "description": "Tut#8 Description",
    6. "published": true
    7. },
    8. ...
    9. ...
    10. ...
    11. {
    12. "id": 1,
    13. "title": "Spring Boot Tut#1",
    14. "description": "Tut#1 Description",
    15. "published": false
    16. }
    17. ]
    • 对于分页和排序组合在一起:/api/tutorials
    1. {
    2. "totalItems": 8,
    3. "tutorials": [
    4. ...
    5. ],
    6. "totalPages": 3,
    7. "currentPage": 1
    8. }

     请访问: 春靴分页和排序示例

    让我们看一下构建此弹簧启动应用程序后的结果:

    – 获取所有具有默认顺序 [id, 降序] 的教程:

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

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

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

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

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

    1. public interface PagingAndSortingRepository extends CrudRepository {
    2. Iterable findAll(Sort sort);
    3. }

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

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

    List findByTitleContaining(String title, Sort sort);

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

    让我们继续探索Sort类。

    弹簧数据排序和排序

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

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

    1. // order by 'published' column - ascending
    2. List tutorials =
    3. tutorialRepository.findAll(Sort.by("published"));
    4. // order by 'published' column, descending
    5. List tutorials =
    6. tutorialRepository.findAll(Sort.by("published").descending());
    7. // order by 'published' column - descending, then order by 'title' - ascending
    8. List tutorials =
    9. tutorialRepository.findAll(Sort.by("published").descending().and(Sort.by("title")));

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

    1. List orders = new ArrayList();
    2. Order order1 = new Order(Sort.Direction.DESC, "published");
    3. orders.add(order1);
    4. Order order2 = new Order(Sort.Direction.ASC, "title");
    5. orders.add(order2);
    6. List tutorials = tutorialRepository.findAll(Sort.by(orders));

    分页和排序

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

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

    1. public interface PagingAndSortingRepository extends CrudRepository {
    2. Page findAll(Pageable pageable);
    3. }

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

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

    1. Page findByPublished(boolean published, Pageable pageable);
    2. Page findByTitleContaining(String title, Pageable pageable);


    有关分页和排序的更多详细信息,请访问:
    春靴分页和排序示例

    弹簧启动应用

    您可以逐步进行操作,也可以在本文中获取源代码:
    弹簧启动,弹簧数据JPA - Rest CRUD API示例

    Spring 项目包含的结构,我们只需要添加一些更改即可使分页正常工作。

    或者,您可以在本教程结束时获取新的 Github 源代码(包括分页和排序)。

    数据模型

    这是我们将要处理的教程实体:

    model/Tutorial.java

    1. package com.bezkoder.spring.data.jpa.pagingsorting.model;
    2. import javax.persistence.*;
    3. @Entity
    4. @Table(name = "tutorials")
    5. public class Tutorial {
    6. @Id
    7. @GeneratedValue(strategy = GenerationType.AUTO)
    8. private long id;
    9. @Column(name = "title")
    10. private String title;
    11. @Column(name = "description")
    12. private String description;
    13. @Column(name = "published")
    14. private boolean published;
    15. public Tutorial() {
    16. }
    17. public Tutorial(String title, String description, boolean published) {
    18. this.title = title;
    19. this.description = description;
    20. this.published = published;
    21. }
    22. public long getId() {
    23. return id;
    24. }
    25. public String getTitle() {
    26. return title;
    27. }
    28. public void setTitle(String title) {
    29. this.title = title;
    30. }
    31. public String getDescription() {
    32. return description;
    33. }
    34. public void setDescription(String description) {
    35. this.description = description;
    36. }
    37. public boolean isPublished() {
    38. return published;
    39. }
    40. public void setPublished(boolean isPublished) {
    41. this.published = isPublished;
    42. }
    43. @Override
    44. public String toString() {
    45. return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
    46. }
    47. }

    支持分页和排序的存储库

    在本教程的早期,我们知道PagingAndSortingRepository ,但是在此示例中,为了保持连续性并利用Spring数据JPA,我们继续使用扩展​​​​​​​PagingAndSortingRepository接口的Jpa存储库

    repository/TutorialRepository.java

    1. package com.bezkoder.spring.data.jpa.pagingsorting.repository;
    2. import java.util.List;
    3. import org.springframework.data.domain.Page;
    4. import org.springframework.data.domain.Pageable;
    5. import org.springframework.data.domain.Sort;
    6. import org.springframework.data.jpa.repository.JpaRepository;
    7. import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;
    8. public interface TutorialRepository extends JpaRepository {
    9. Page findByPublished(boolean published, Pageable pageable);
    10. Page findByTitleContaining(String title, Pageable pageable);
    11. List findByTitleContaining(String title, Sort sort);
    12. }

    在上面的代码中,我们将添加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

    1. package com.bezkoder.spring.data.jpa.pagingsorting.controller;
    2. import org.springframework.data.domain.Sort;
    3. import org.springframework.data.domain.Sort.Order;
    4. ...
    5. import com.bezkoder.spring.data.jpa.pagingsorting.model.Tutorial;
    6. import com.bezkoder.spring.data.jpa.pagingsorting.repository.TutorialRepository;
    7. @RestController
    8. @RequestMapping("/api")
    9. public class TutorialController {
    10. @Autowired
    11. TutorialRepository tutorialRepository;
    12. private Sort.Direction getSortDirection(String direction) {
    13. if (direction.equals("asc")) {
    14. return Sort.Direction.ASC;
    15. } else if (direction.equals("desc")) {
    16. return Sort.Direction.DESC;
    17. }
    18. return Sort.Direction.ASC;
    19. }
    20. @GetMapping("/sortedtutorials")
    21. public ResponseEntity> getAllTutorials(@RequestParam(defaultValue = "id,desc") String[] sort) {
    22. try {
    23. List orders = new ArrayList();
    24. if (sort[0].contains(",")) {
    25. // will sort more than 2 columns
    26. for (String sortOrder : sort) {
    27. // sortOrder="column, direction"
    28. String[] _sort = sortOrder.split(",");
    29. orders.add(new Order(getSortDirection(_sort[1]), _sort[0]));
    30. }
    31. } else {
    32. // sort=[column, direction]
    33. orders.add(new Order(getSortDirection(sort[1]), sort[0]));
    34. }
    35. List tutorials = tutorialRepository.findAll(Sort.by(orders));
    36. if (tutorials.isEmpty()) {
    37. return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    38. }
    39. return new ResponseEntity<>(tutorials, HttpStatus.OK);
    40. } catch (Exception e) {
    41. return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    42. }
    43. }
    44. }

    将分页和排序结合在一起的控制器怎么样?
    请访问: 春靴分页和排序示例

    结论

    在这篇文章中,我们学习了如何使用弹簧数据JPA,排序类和可分页界面在弹簧启动应用程序中按多个列进行排序/排序。

    我们还看到,这支持了一种无需样板代码即可制作排序、分页和筛选方法的好方法。JpaRepository

    带注释的自定义查询:
    春季 JPA @Query示例:春季启动中的自定义查询@Query

    您还可以在本文中了解如何:
    - 分页和过滤。
    – 在这篇文章中处理异常。
    – 通过本教程在 AWS 上部署此春季启动应用程序(免费)。

    学习愉快!再见。

    延伸阅读

    对于分页和排序:
    弹簧靴分页和排序示例

    源码

    您可以在 Github 上找到本教程的完整源代码。

    更多派生查询,请参见:
    弹簧启动中的 JPA 存储库查询示例

    您可以将代码用作以下帖子的附加功能:
    – 弹簧启动,弹簧数据 JPA,H2 示例
    – 弹簧启动、弹簧数据 JPA、MySQL 示例
    – 弹簧启动、弹簧数据 JPA、PostgreSQL 示例
    – 弹簧启动、弹簧数据 JPA、SQL Server 示例
    – 弹簧启动、弹簧数据 JPA、Oracle 示例

    关联:
    – 使用 JPA 的弹簧启动一对一示例,休眠
    – 使用 JPA 的弹簧启动一对多示例,使用 JPA 的
    弹簧启动多对多示例,休眠

    单元测试:
    – JPA 回收的弹簧启动单元测试
    – 静止控制器的弹簧启动单元测试

  • 相关阅读:
    C++ 使用c++类模板实现动态数组-可实现自定义数据类型存储
    机器学习的第一节基本概念的相关学习
    强化学习:A2C求解MountainCar-v0小车上山问题
    径流数据整理
    计算机毕业设计Java自由教学平台(源码+系统+mysql数据库+lw文档)
    PyTorch: 张量的变换、数学运算及线性回归
    RocketMq最强总结 带你rocket从入门到入土为安
    Linux之jar包之启动与停止脚本
    Django分页功能的使用和自定义分装
    docker搭建sftp服务器
  • 原文地址:https://blog.csdn.net/allway2/article/details/127423011