我正在尝试使用相同的uri但不同的类型创建两个休息端点。 第一个将通过EAN(Int)搜索第二个将通过id(String)搜索。我可以以某种方式超载端点吗?我使用Spring Boot with Kotlin
@GetMapping("/book/{ean}")
fun getABookByEan(@PathVariable ean: Int) : ResponseEntity<*> {
repository.getByEan(ean)?.let {
return ResponseEntity.status(HttpStatus.OK).body(it)
}
throw ItemNotFoundException()
}
@GetMapping("/book/{id}")
fun getABookById(@PathVariable id: String) : ResponseEntity<*> {
repository.getById(id)?.let {
return ResponseEntity.status(HttpStatus.OK).body(it)
}
throw ItemNotFoundException()
}
在此之后,我得到了一个例外,即为同一个端点映射了多个方法。
... NestedServletException:请求处理失败;嵌套异常是java.lang.IllegalStateException:为HTTP路径映射的不明确的处理程序方法...
答案 0 :(得分:3)
我发现如果我想坚持使用API,那么唯一的方法是使用正则表达式。
@GetMapping("/book/{ean:[\\d]+}")
@GetMapping("/book/{id:^[0-9a-fA-F]{24}$}")
使用它可以将MongoDB生成的十六进制24字符与简单数字区分开来。如果有人找到更好的方式,请在评论中告诉我。
答案 1 :(得分:1)
从HTTP的角度来看,它是一个端点,因为它是基于文本的协议,路径参数始终是一个字符串。因此,Spring抛出异常。
要处理此问题,您可以在方法体内识别参数类型:
@GetMapping("/book/{identifier}")
fun getABookById(@PathVariable identifier: String) : ResponseEntity<*> {
try {
val id = identifier.toInt()
// id case
repository.getById(id)?.let {
return ResponseEntity.status(HttpStatus.OK).body(it)
}
} catch (e: NumberFormatException) {
// ean case
repository.getByEan(identifier)?.let {
return ResponseEntity.status(HttpStatus.OK).body(it)
}
}
throw ItemNotFoundException()
}
或将ean或id传递给@RequestParam,例如/ book?ean = abcdefg,/ book?id = 5.
答案 2 :(得分:0)
在映射级别上无法执行此操作。可能你应该尝试以下路径:
/book/ean/{ean}
/book/id/{id}
或者只是
/book/id/{someUniversalId}
然后在可执行代码中区分不同类型的ID。
答案 3 :(得分:0)
开发查询过滤器/查询条件以处理类似以下内容将是有益的:
/book?q=ean+eq+abcdefg (meaning ean=abcdefg)
/book?q=id+gt+1000 (meaning id>1000)
等等。
答案 4 :(得分:0)
如何使用矩阵参数?
因此,对于id,您可以使用path参数-/books/{id}
对于ean,矩阵参数-/books;ean={ean}
实际上,对于id,您也可以使用矩阵参数-/books;{id}
或/books;id={id}
矩阵参数的通用网址-/{resource-name}[;{selector}]/
源-Apigee REST API设计最佳实践