Java 了解 Spring MVC 的 @RequestMapping POST 是如何工作的
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9738442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding How Spring MVC's @RequestMapping POST Works
提问by limc
I have a simple Controller that looks like this:-
我有一个简单的控制器,看起来像这样:-
@Controller
@RequestMapping(value = "/groups")
public class GroupsController {
// mapping #1
@RequestMapping(method = RequestMethod.GET)
public String main(@ModelAttribute GroupForm groupForm, Model model) {
...
}
// mapping #2
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String changeGroup(@PathVariable Long id, @ModelAttribute GroupForm groupForm, Model model) {
...
}
// mapping #3
@RequestMapping(method = RequestMethod.POST)
public String save(@Valid @ModelAttribute GroupForm groupForm, BindingResult bindingResult, Model model) {
...
}
}
Basically, this page has the following functionalities:-
基本上,此页面具有以下功能:-
- User visits main page (
/groups GET
). - User creates a new group (
/groups POST
) or selects a specific group (/groups/1 GET
). - User edits an existing group (
/groups/1 POST
).
- 用户访问主页 (
/groups GET
)。 - 用户创建新组 (
/groups POST
) 或选择特定组 (/groups/1 GET
)。 - 用户编辑现有组 (
/groups/1 POST
)。
I understand how both GET request mappings work here. Mapping #2 is defined, otherwise (/groups/1 GET
) will cause a "No mapping found" exception.
我了解 GET 请求映射在这里是如何工作的。映射 #2 已定义,否则 ( /groups/1 GET
) 将导致“未找到映射”异常。
What I'm trying to understand here is why mapping #3 handles both (/groups POST
) and (/groups/1 POST
)? It makes sense that it should handle (/groups POST
) here since the request mapping matches the URI. Why (/groups/1 POST
) isn't causing a "No mapping found" exception being thrown here? In fact, it almost seems like any POST with URI beginning with /groups (ex: /groups/bla/1 POST
) will also be handled by mapping #3.
我想在这里理解的是为什么映射 #3 处理 ( /groups POST
) 和 ( /groups/1 POST
) ?/groups POST
由于请求映射与 URI 匹配,因此它应该处理 ( )是有道理的。为什么 ( /groups/1 POST
) 不会导致此处抛出“未找到映射”异常?事实上,似乎任何以 /groups 开头的 URI 的 POST(例如:)/groups/bla/1 POST
也将通过映射 #3 来处理。
Can someone provide a clear explanation of this to me? Thanks much.
有人可以向我提供清楚的解释吗?非常感谢。
CLARIFICATION
澄清
I understand the fact that I can use more appropriate methods (like GET, POST, PUT or DELETE)... or I can create yet another request mapping to handle /groups/{id} POST
.
我明白我可以使用更合适的方法(如 GET、POST、PUT 或 DELETE)...或者我可以创建另一个请求映射来处理/groups/{id} POST
.
However, what I want to really know is...
然而,我真正想知道的是……
.... "Why does mapping #3 handle /groups/1 POST
too?"
.... “为什么映射 #3 也能处理/groups/1 POST
?”
The "closest match" reasoning don't seem to hold true because if I remove mapping #2, then I would think mapping #1 will handle /groups/1 GET
, but it doesn't and it causes a "No mapping found" exception.
“最接近匹配”的推理似乎不成立,因为如果我删除映射 #2,那么我认为映射 #1 会处理/groups/1 GET
,但它不会,并且会导致“未找到映射”异常。
I'm just a little stumped here.
我只是有点难住这里。
采纳答案by Ralph
This is complicated, I think it is better to read the code.
这个比较复杂,我觉得还是看代码比较好。
In Spring 3.0 The magic is done by method public Method resolveHandlerMethod(HttpServletRequest request)
of the inner class ServletHandlerMethodResolver
of org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
.
在Spring 3.0的魔术是由法进行public Method resolveHandlerMethod(HttpServletRequest request)
内部类ServletHandlerMethodResolver
的org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
。
An instance of this class exists for every Request Controller Class, and has a field handlerMethods
that contains a list of all the request methods.
每个请求控制器类都存在此类的一个实例,并且有一个handlerMethods
包含所有请求方法列表的字段。
But let me summarize how I understand it
但让我总结一下我是如何理解它的
- Spring first checks if at least one handler method matches (this can contain false negatives)
- Then it creates a map of all really matching handler methods
- Then it sorts the map by request path:
RequestSpecificMappingInfoComparator
- and takes the first one
- Spring 首先检查是否至少有一个处理程序方法匹配(这可能包含误报)
- 然后它创建所有真正匹配的处理程序方法的映射
- 然后它按请求路径对地图进行排序:
RequestSpecificMappingInfoComparator
- 并取第一个
The sorting works this way: the RequestSpecificMappingInfoComparator
first compares the path with the help of an AntPathMatcher
, if two methods are equal according to this, then other metrics (like number of parameters, number of headers, etc.) are taken into account with respect to the request.
排序是这样工作的:第RequestSpecificMappingInfoComparator
一个在 an 的帮助下比较路径AntPathMatcher
,如果两个方法根据 this 相等,那么其他指标(如参数数量、标题数量等)将考虑到要求。
回答by PaiS
Spring tries to find the mapping which matches the closest.
Hence, in your case of any POST request, the only map found for the request type is Mapping# 3.
Neither of Mapping 1 or Mapping 2 matches your request type, and hence are ignored.
May be you can try removing the Mapping #3, and see that Spring throws a runtime error since it does not find a match!
Spring 尝试找到最接近的映射。
因此,在您的任何 POST 请求的情况下,为请求类型找到的唯一映射是 Mapping# 3。 Mapping 1 或 Mapping 2 都不匹配您的请求类型,因此被忽略。也许您可以尝试删除映射 #3,并看到 Spring 抛出运行时错误,因为它没有找到匹配项!
回答by AdrianS
add @PathVariable to the Long id parameter in mapping #2
将@PathVariable 添加到映射 #2 中的 Long id 参数
回答by Eric Winter
I would add a PUT mapping for /groups/{id}. I guess POST would work too but not strictly correct from a HTTP perspective.
我会为 /groups/{id} 添加一个 PUT 映射。我猜 POST 也可以工作,但从 HTTP 的角度来看并不严格正确。
adding @RequestMapping("/{id}", POST) should cover it?
添加@RequestMapping("/{id}", POST) 应该覆盖它吗?