我有一个简单的控制器,如下所示: -
@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) {
...
}
}
基本上,此页面具有以下功能: -
/groups GET
)。/groups POST
)或选择特定组(/groups/1 GET
)。/groups/1 POST
)。我理解GET请求映射在这里是如何工作的。定义了映射#2,否则(/groups/1 GET
)将导致“找不到映射”异常。
我在这里想要理解的是为什么映射#3同时处理(/groups POST
)和(/groups/1 POST
)?因为请求映射与URI匹配,所以它应该在这里处理(/groups POST
)。为什么(/groups/1 POST
)没有导致在此处抛出“未找到映射”异常?实际上,似乎任何带有以/ groups开头的POST(例如:/groups/bla/1 POST
)的POST也将通过映射#3来处理。
有人可以向我提供明确的解释吗?非常感谢。
澄清
我理解我可以使用更合适的方法(如GET,POST,PUT或DELETE)......或者我可以创建另一个请求映射来处理/groups/{id} POST
。
然而,我真正想知道的是......
.... “为什么映射#3也处理/groups/1 POST
?”
“最接近的匹配”推理似乎不成立,因为如果我删除映射#2,那么我认为映射#1将处理/groups/1 GET
,但它没有,它会导致“否”映射找到“例外。
我只是有点难过。
答案 0 :(得分:19)
这很复杂,我认为最好阅读代码。
在Spring 3.0中,魔术是由public Method resolveHandlerMethod(HttpServletRequest request)
的内部类ServletHandlerMethodResolver
的方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
完成的。
每个请求控制器类都存在此类的实例,并且具有包含所有请求方法列表的字段handlerMethods
。
但让我总结一下我的理解
RequestSpecificMappingInfoComparator
排序以这种方式工作:RequestSpecificMappingInfoComparator
首先在AntPathMatcher
的帮助下比较路径,如果两个方法根据此相等,则其他指标(如参数数量,数量)关于请求,会考虑标题等。
答案 1 :(得分:2)
Spring试图找到与最接近的匹配的映射。
因此,在任何POST请求的情况下,为请求类型找到的唯一映射是Mapping#3。
映射1或映射2都不匹配您的请求类型,因此将被忽略。
也许你可以尝试删除Mapping#3,并看到Spring抛出运行时错误,因为它找不到匹配!
答案 2 :(得分:1)
我会为/ groups / {id}添加一个PUT映射。我认为POST也可以工作,但从HTTP的角度来看并不严格。
添加@RequestMapping(“/ {id}”,POST)应该涵盖它吗?
答案 3 :(得分:-3)
将@PathVariable添加到映射#2
中的Long id参数