使用Spring处理REST应用程序中映射的模糊处理程序方法

27

我尝试使用以下代码:

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Brand getBrand(@PathVariable Integer id) {
    return brandService.getOne(id);
}

@RequestMapping(value = "/{name}", method = RequestMethod.GET)
public List<Brand> getBrand(@PathVariable String name) {
    return brandService.getSome(name);
}

但我遇到了这样的错误,我该怎么办?

java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/api/brand/1': {public java.util.List com.zangland.controller.BrandController.getBrand(java.lang.String), public com.zangland.entity.Brand com.zangland.controller.BrandController.getBrand(java.lang.Integer)}
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:375) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
3个回答

58

Spring无法区分请求 GET http://localhost:8080/api/brand/1 将由 getBrand(Integer) 还是 getBrand(String) 处理,因为您的映射不明确。

尝试使用查询参数来调用 getBrand(String) 方法。这似乎更合适,因为您正在执行一个查询:

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Brand getBrand(@PathVariable Integer id) {
    return brandService.getOne(id);
}

@RequestMapping(method = RequestMethod.GET)
public List<Brand> getBrands(@RequestParam(value="name") String name) {
    return brandService.getSome(name);
}

按照上述方法:

  • GET http://localhost:8080/api/brand/1这样的请求将由getBrand(Integer)处理。
  • GET http://localhost:8080/api/brand?name=nike这样的请求将由getBrand(String)处理。

提示:通常情况下,对于资源的集合,使用复数名词更好。因此,应该使用/brands而不是/brand


如果控制器也有一个名为getAll()的方法,其URL为http://localhost:8080/api/brand,那么如何同时拥有这三个方法(getAll()和按名称获取品牌的getBrand()将具有冲突的路径)? - fireball.1
@fireball.1 name 查询参数的存在(或不存在)将决定服务器是获取所有品牌(还是按名称筛选品牌)。 - cassiomolin
似乎不起作用,我在这里详细描述了我的问题:https://stackoverflow.com/questions/64913401/have-controller-methods-to-getall-getbyid-and-getbyemail-in-the-same-controller - fireball.1
@fireball.1 我已经发布了你的问题的答案。希望能有所帮助。 - cassiomolin

13
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Brand getBrand(@PathVariable Integer id) {
    return brandService.getOne(id);
}

@RequestMapping(value = "/{name}", method = RequestMethod.GET)
public List<Brand> getBrand(@PathVariable String name) {
    return brandService.getSome(name);
}
当你运行该应用程序并访问你尝试编码的端点时,你会发现以下内容:'http://localhost:8086/brand/1'和'http://localhost:8086/brand/FooBar'对应于相同的URL格式(可以描述为协议+端点+'brand'+)。 因此,SpringBoot无法确定是否使用字符串数据类型或整数来调用'getBrand'函数。 为了解决这个问题,建议您像@cassiomolin提到的那样使用查询参数,或者为两种调用分别设置单独的路径。 这可能违反REST原则,但是假设你只是在做一个示例应用程序,这是另一个解决方法。
@RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
public Brand getBrand(@PathVariable Integer id) {
    return brandService.getOne(id);
}

@RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
public List<Brand> getBrand(@PathVariable String name) {
    return brandService.getSome(name);
}

这对我有用。


0
Spring可以通过指定如何区分变量来处理这个问题,你可以使用正则表达式来实现这一点。
@GetMapping("/{id:\\d+}")
public Brand getBrand(@PathVariable Integer id) {
    return brandService.getById(id);
}

@GetMapping("/{name:.*\\D.*}")
public List<Brand> getBrand(@PathVariable String name) {
    return brandService.getByName(name);
}

在上面的例子中,id必须只包含数字,而name必须至少包含一个非数字字符。

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