Spring 4中REST控制器中的可选@PathVariable

3
我正在编写一个Rest服务(HTTP Get端点),以下uri执行以下操作:
http://localhost:8080/customers/{customer_id}
  1. 获取通过uri传递的customer_id的详细信息。
  2. 如果未传递customer_id(http://localhost:8080/customers),则获取所有客户的详细信息。

代码:

@RequestMapping(method = RequestMethod.GET, value = "customers/{customer_id}")
public List<Customer> getCustomers(
@PathVariable(name = "customer_id", required = false) final String customerId) {
LOGGER.debug("customer_id {} received for getCustomers request", customerId);

}

然而,对于上述代码,对于第二种情况,控制流正在流向getCustomers()。

注意:我正在使用Java8和spring-web 4.3.10版本。

非常感谢您的帮助。

3个回答

6

可选的 @PathVariable 只有在您想要将 GET /customers/{customer_id}GET customers 映射到单个 Java 方法时才会使用。

如果您不发送 customer_id,则无法发送请求将被发送到 GET /customers/{customer_id}

所以在你的情况下,它将是:

@RequestMapping(method = RequestMethod.GET, value = {"/customers", "customers/{customer_id}"})
public List<Customer> getCustomers(@PathVariable(name = "customer_id", required = false) final String customerId) {
    LOGGER.debug("customer_id {} received for getCustomers request", customerId);
}

public abstract boolean required

路径变量是否必填。

默认为true,如果请求中缺少路径变量,则会引发异常。如果您希望在此情况下使用null或Java 8 java.util.Optional,请将其更改为false。例如可以在为不同请求提供服务的ModelAttribute方法上使用。

您可以使用java8中的nullOptional


value = {"/customers", "customers/{customer_id}"}) 这是 Ant 风格。 - Lova Chittumuri
谢谢 @ByeBye.. 运作得很好。 - technoJ
@ByeBye 刚刚注意到当我将请求映射值设置为数组时出现了问题。我已经注册了一个类级别的请求映射,而方法级别的请求映射如下所示:@RequestMapping(method = RequestMethod.GET, value = {"/", "/{customer_id}"})。当我调用http://localhost:8080/customers(没有尾随斜杠)时,端点返回404。这里有什么问题吗? - technoJ
@ByeBye,PathVariable如何接受required false/true这样的参数?我这里编译时出现了错误。 - Rajesh Hatwar
@RajeshHatwar https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html 文档指出该参数已经存在。 - ByeBye

1
这可能会帮助那些试图使用多个可选路径变量的人。
如果您有多个变量,您可以始终接受多个路径。 例如:
@GetMapping(value = {"customers/{customerId}&{startDate}&{endDate}",
"customers/{customerId}&{startDate}&",
"customers/{customerId}&&{endDate}",
"customers/{customerId}&&"
})
public Customer getCustomerUsingFilter(@PathVariable String customerId, @PathVariable Optional<Date> startDate, @PathVariable Optional<Date> endDate)

然后您将使用所有路径分隔符(在此示例中为&)调用此URL。
例如: GET /customers/1&& GET /customers/1&&2018-10-31T12:00:00.000+0000 GET /customers/1&2018-10-31T12:00:00.000+0000& GET /customers/1&2018-10-31T12:00:00.000+0000&2018-10-31T12:00:00.000+0000

0

您应该在这里创建两个端点来处理单独的请求:

@GetMapping("/customers")
public List<Customer> getCustomers() {
LOGGER.debug("Fetching all customer");  
}

@GetMapping("/customers/{id}")
public List<Customer> getCustomers(@PathVariable("id") String id) {
LOGGER.debug("Fetching customer by Id {} ",id);  
}

@GetMapping 相当于 @RequestMapping(method = RequestMethod.GET),而 @GetMapping("/customers/{id}") 相当于 @RequestMapping(method = RequestMethod.GET, value = "customers/{id}")

更好的做法是这样的:

@RestController
@RequestMapping("/customers")
public class CustomerController {

    @GetMapping
    public List<Customer> getAllCustomers() {
    LOGGER.debug("Fetching all customer");  
    }

    @GetMapping("/{id}")
    public Customer getCustomerById(@PathVariable("id") String id) {
    LOGGER.debug("Fetching customer by Id {} ",id);  
    }

我最初是这样做的,但是这两个Java方法都旨在执行相同的操作。我正在寻找一个单一的Java方法,以避免代码重复。像@ByeBye建议的那样,我正在寻找类似的东西。 - technoJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接