在 Spring MVC 休息服务上,我在尝试匹配超出我配置的 RequestMapping 值的任何内容时遇到问题。
例如我有这个:
@RequestMapping(value = "{configKey}/{arguments:.*}", method = RequestMethod.GET)
这表示匹配第二个路径变量之外的任何内容。问题是这个例如可以正常使用:
get("/test/document")
最终结果是 404:
get("/test/document/download")
奇怪的是 Spring 无法处理这个正则表达式。我实际上尝试了很多解决方案,但没有一个起作用。
之前我在 JAX-RS 上有这样的配置:
@Path("/{configKey}/{arguments:.*}")
一切都很好,但现在我正在迁移并遇到这个问题。
有谁知道发生了什么事以及如何解决这个问题?
编辑:
添加
{configKey}/**
- 不起作用
添加
{configKey}/{arguments}/**
有效,但对于例如如果我打电话:
get("/test/document/download")
我只得到 test
作为我的配置键和 document
作为参数。在争论中,我希望得到{configKey}
之外的所有内容。这可以是任何东西,例如它应该在任何情况下都有效:
get("/test/document")
get("/test/document/download")
get("/test/document/download/1")
get("/test/document/download/1/2")
get("/test/whatever/xxx/1/2/etc")
它正在使用 JAX-RS 的配置:
@Path("/{configKey}/{arguments:.*}")
我找到了一个解决方法,它不是永久的解决方案,我认为这是 Spring 中的一个错误,我提出了一个 Jira,但在它在这里修复之前它是:
我必须像这样定义我的请求映射:
@RequestMapping(value = "{configKey}/**", method = RequestMethod.GET)
所以基本上匹配路径中第一个变量之后的所有内容。
然后:
String arguments = pathMatcher.extractPathWithinPattern(
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString(),
request.getPathInfo());
其中 pathMatcher 是 Spring 使用的 AntPathMatcher 的实例。
现在调用 HTTP GET 例如这条路:
get("/test/leaderboard/user/mq/frankie1")
我有:
configKey = test
arguments = leaderboard/user/mq/frankie1
对于任何来到这里寻找答案,但意识到当前答案来自 2015 年的人来说,由于
PathPattern
,新版本的 Spring 对此进行了改进。
https://spring.io/blog/2020/06/30/url-matching-with-pathpattern-in-spring-mvc
PathPattern 与 AntPathMatcher 语法兼容,但以下内容除外:
支持附加语法来匹配并捕获末尾的 0 个或多个路径段,例如“/foo/{*spring}”。这作为 REST API 中的包罗万象的模式非常有用,可以通过 @PathVariable 访问捕获的路径段。
仅在模式末尾允许支持多段匹配的“**”。在为给定请求选择最接近的匹配时,这有助于消除大多数歧义原因。
特别是,
@GetMapping(path = "/foo/{*spring}")
对我来说很有效(@RequestMapping
也可以),它将 @PathVariable String spring
注入到你的方法中。因此,如果我使用 GET /foo/1/2/3
调用 API,则 String spring
将等于 /1/2/3
(是的,带有前导斜杠)
Spring 使用 AntPathMatcher,映射使用以下规则匹配 URL:
1. ? matches one character
2. * matches zero or more characters
3. ** matches zero or more 'directories' in a path
这就是我配置请求映射url的方式,我在我的电脑上测试过,它有效,你可以根据你的需要自定义。
@RequestMapping(value = "/new-ajax/**", method = RequestMethod.GET)
测试用例
/new-ajax/document/1
/new-ajax/document/download/1
/new-ajax/document/download/1/2
/new-ajax/test/whatever/xxx/1/2/etc