您将如何使用 Spring Boot 处理仅具有可选查询参数的 REST API?

Posted

技术标签:

【中文标题】您将如何使用 Spring Boot 处理仅具有可选查询参数的 REST API?【英文标题】:How would you handle a REST API with only optional query params with Spring Boot? 【发布时间】:2020-06-04 23:58:40 【问题描述】:

我想构建一个返回 Order 对象的简单端点,我可以在其中通过单个查询参数或多个查询参数的组合搜索此订单。所有这些查询参数都是可选的,原因是不同的人会根据不同的 Id 访问这些订单。

例如: /order/items?itemId=itemId&orderId=orderId&deliveryId=deliveryId&packetId=packetId

@GetMapping(path = "/order/items", produces = "application/json")
public Order getOrders(@RequestParam Optional<String> itemId,
                              @RequestParam Optional<String> orderId,
                              @RequestParam Optional<String> deliveryId,
                              @RequestParam Optional<String> packetId)  

当然,我也可以跳过 Java Optional 并使用 @RequestParam(required = false),但这里的问题是如何避免检查查询参数是否为空的 if-else.isPresent() 噩梦?或者是否有一种优雅的方式,取决于参数的星座,进一步传递给我的服务和 Spring Data JPA 存储库。

【问题讨论】:

我总是像 WHERE (:myParam IS NULL OR TABLE.COLUMN = :myParam ) 这样为可选参数构建我的 SQL...这样您的查询处理 null 并且您可以从该查询中获得更多信息..所以我实际上会使用@RequestParam(required = false) 但是搜索端点应该真正返回一个数组,而不是单个项目 将空值传递给查询和let the query handle it。 好吧,在这种情况下,如果存在的话,它应该只是一个订单。 如果它是一个搜索端点(它是),它应该返回一个结果数组......它也被称为getOrders,它也会让人们相信它返回多个......跨度> 【参考方案1】:

为了尽量减少方法中的参数数量,您可以将查询参数定义为类的字段:

@Data
public class SearchOrderCriteria 
    private String itemId;
    private String orderId;
    private String deliveryId;
    private String packetId;

然后在您的控制器方法中接收此类的实例:

@GetMapping(path = "/order/items", produces = "application/json")
public ResponseEntity<OrderInfo> getOrder(SearchOrderCriteria searchCriteria) 
    OrderInfo order = orderService.findOrder(searchCriteria)
    return ResponseEntity.ok(order);

而且,在你的服务中,为了避免一堆if-else,你可以使用query by example:

public OrderInfo findOrder(SearchOrderCriteria searchCriteria) 

    OrderInfo order = new OrderInfo();
    order.setItemId(searchCriteria.getItemId());
    order.setOrderId(searchCriteria.getOrderId());
    order.setDeliveryId(searchCriteria.getDeliveryId());
    order.setPacketId(searchCriteria.getPacketId());

    Example<OrderInfo> example = Example.of(order);
    return orderRepository.findOne(example);

【讨论】:

我喜欢这种方法,但也许我还不了解整个情况:) 我仍然很困惑如何根据获取端点中的查询参数来填充 SearchCriteria 中的字段? @lapadets 查看 Spring Data 文档以获取有关 query by example 工作原理的更多详细信息。 谢谢!你的回答对我帮助很大!【参考方案2】:

我的小建议是避免使用过于通用的 API,例如您可以将映射拆分为多个端点,例如:/order/delivery/itemId/itemId 和 /order/delivery/deliveryId/deliveryId 和 /order /delivery/packetId/packetId 并处理您需要在客户端调用的。

【讨论】:

感谢您的建议 - 我通常也会这样做,但问题是它需要是一个端点并且不会从多个客户端调用。 在这种情况下,您可以将所有参数放入非空值的列表过滤器中,例如:List listWithoutNulls = list.stream() .filter(Objects::nonNull) .collect(Collectors.toList ()) 然后继续策略模式以选择需要调用的数据源

以上是关于您将如何使用 Spring Boot 处理仅具有可选查询参数的 REST API?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot Actuator 构建 RESTful Web 服务

如何在具有 JDBC 安全性的 Spring Boot 中使用 Flyway?

如何使用spring boot plugin 2.0.x从一个具有不同依赖项的gradle项目生成2个jar

Spring Boot下的一种导出Excel文件的代码框架

java VFS的版本,当您将Spring Boot作为java -jar yourapp.jar运行时也可以使用

如何使用spring boot后端使角度应用程序仅接收来自局域网的请求?