Spring Pageable Sort 更改属性名称

问题描述 投票:0回答:2

有没有办法映射 Sort 对象的属性?举个小例子:

a Dto

public class OrderDto {
  private long totalAmount;
  private long openAmount;
}

和一个实体

@Entity
public class Order {
  private long amount;
}

和控制器

@RestController
public class OrderController {


  @GetMapping("/orders")
  public Page<OrderDto> findOrders(Pageable pageable) {
   // Do something 
  }
}

我现在会打电话给

/orders?sort=totalAmount,desc

是否可以映射排序属性,在本例中,将 Dto 中的

totalAmount
映射到仅
amount
,以便以一种迷人的方式将其用于生成的 JPA 查询?

java spring spring-data-jpa dto spring-restcontroller
2个回答
2
投票

我不知道我是否正确回答了你的问题,但是...

我理解正确吗,您希望将请求参数

sort
与值
totalAmount,desc
映射,以便通过给定
Sort
对象的
Pageable
对象作为
amount
使用(顺序为
desc
)?

由于您在帖子中提到的名称,我希望您的类路径上有 Spring Data。

IDKFS,但也许类

SortHandlerMethodArgumentResolverCustomizer
可以帮助您自定义
SortHandlerMethodArgumentResolver
的方式,您可以像您想要的那样映射请求参数。

如果没有,应该可以提供一个

SortHandlerMethodArgumentResolver
类型的 @Bean 来实现您想要的行为。

我不完全确定框架是否允许覆盖您需要自定义的特定部分,但在我看来值得一看。 :)


0
投票

我面临着同样的情况,我在互联网上找到的答案都没有足够清楚地说明如何使用 Spring 完成此操作,因此为了使情况更清楚,我将发布我想出的解决方案。

什么时候需要这样的事情?

当在 API 中使用 DTO 为消费者提供对象的某种表示时,就会出现所描述的情况。现在,当消费者尝试使用其知道的对象属性来查询有关该对象的 API 时,可能会导致 500 错误或误导,因为 API 可能无法立即识别消费者发送的对象或属性

。您可以摆脱 DTO 并解决这个问题,但没有人愿意失去那个抽象层。 在示例中,API 将字段

amount

转换为

totalAmount
,但是当查询
totalAmount
(客户端不必知道转换或属性的真实名称)时,API 通过服务和存储库,无法找到该属性
totalAmount
Spring 中如何处理这个问题?

那么,您将如何以符合 Spring Boot 的方式实现这一点呢?从逻辑上讲,如果在控制器层将对象转换为其 DTO 表示,则应该有一种方法可以在同一表面级别转换查询,而不是将问题向下传递给服务层或存储库层处理。这就是要走的路。

第一件事是创建一个

SortArgumentResolver

,它负责修改作为排序参数传递的属性,同时保留其余排序参数(小心复杂的场景,在不同的请求上可能存在冲突的属性)。

public class OrderSortArgumentResolver implements SortArgumentResolver {
    private final SortArgumentResolver delegate;

    public OrderSortArgumentResolver(SortArgumentResolver delegate) {
        this.delegate = delegate;
    }

    @Override
    @NonNull
    public boolean supportsParameter(MethodParameter parameter) {
        return delegate.supportsParameter(parameter);
    }

    @Override
    @NonNull
    public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeRequest webRequest, WebDataBinderFactory binderFactory) {
        Sort originalSort = delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        Sort modifiedSort = Sort.unsorted();

        if(!originalSort.isEmpty()) {
            // INFO: this will retain any other sort parameter aside from the one being modified
            for (Sort.Order order : originalSort) {
                if (order.getProperty().equals("totalAmount")) {
                    modifiedSort = modifiedSort.and(Sort.by(order.getDirection(), "amount"));
                } else {
                    modifiedSort = modifiedSort.and(Sort.by(order.getDirection(), order.getProperty()));
                }
            }
        }

        return modifiedSort;
    }
}

获得参数解析器后,您需要将其添加到应用程序配置中。

@Configuration public class WebConfig implements WebMvcConfigurer { private final SortArgumentResolver sortArgumentResolver; public WebConfig(SortArgumentResolver sortArgumentResolver) { this.sortArgumentResolver = sortArgumentResolver; } @Override public void addArgumentResolver(List<HandlerMethodArgumentResolver> resolvers) { // INFO: this will handle paged requests PageableHandlerMethodArgumentResolver pageableResolver = new PageableHandlerMethodArgumentResolver(new OrderSortArgumentResolver(sortArgumentResolver)); resolvers.add(pageableResolver); //INFO: this will handle any other requests resolvers.add(new OrderSortArgumentResolver(sortArgumentResolver)); } }

希望这对遇到同样情况的人有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.