相同的其他端点具有不同的PathVariable

我试图做两个相同的uri,但不同类型的休息端点。 第一个将通过EAN(Int)进行搜索,第二个将通过id(String)进行搜索。 我能否以某种方式超载端点? 我和Kotlin一起使用Spring Boot

@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路径映射的模糊处理程序方法…

从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() } 

或者像@RequestParam一样传递ean或者id / book?ean = abcdefg,/ book?id = 5。

在映射层面上做不到这一点。 可能你应该尝试像下面这样的路径:

 /book/ean/{ean} /book/id/{id} 

或者只是

 /book/id/{someUniversalId} 

然后在可执行代码中区分不同类型的ID。

我发现唯一的方法是正则表达式,如果我想坚持我的API。

 @GetMapping("/book/{ean:[\\d]+}") @GetMapping("/book/{id:^[0-9a-fA-F]{24}$}") 

有了它,MongoDB生成的十六进制24个字符就可以与简单的数字区分开来。 如果有人找到更好的方法,让我知道在评论中。

开发一个查询过滤器/查询条件将是有益的,以处理类似于:

 /book?q=ean+eq+abcdefg (meaning ean=abcdefg) /book?q=id+gt+1000 (meaning id>1000) 

等等。