了解Spring MVC的@RequestMapping POST如何工作

时间:2012-03-16 13:49:27

标签: java spring spring-mvc request-mapping

我有一个简单的控制器,如下所示: -

@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,但它没有,它会导致“否”映射找到“例外。

我只是有点难过。

4 个答案:

答案 0 :(得分:19)

这很复杂,我认为最好阅读代码。

在Spring 3.0中,魔术是由public Method resolveHandlerMethod(HttpServletRequest request)的内部类ServletHandlerMethodResolver的方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter完成的。

每个请求控制器类都存在此类的实例,并且具有包含所有请求方法列表的字段handlerMethods

但让我总结一下我的理解

  • Spring首先检查是否至少有一个处理程序方法匹配(这可能包含漏报)
  • 然后它会创建一个所有真正匹配的处理程序方法的地图
  • 然后按请求路径对地图进行排序: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参数