了解Spring MVC的@RequestMapping POST的工作原理

2022-09-01 10:03:56

我有一个简单的控制器,看起来像这样:-

@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同时处理()和()?它应该在这里处理()是有道理的,因为请求映射与URI匹配。为什么 () 不会导致此处引发“未找到映射”异常?事实上,似乎任何以 /groups 开头的 URI 的 POST(例如:)也将通过映射 #3 进行处理。/groups POST/groups/1 POST/groups POST/groups/1 POST/groups/bla/1 POST

有人可以向我提供明确的解释吗?非常感谢。

澄清

我理解我可以使用更合适的方法(如GET,POST,PUT或DELETE)的事实......或者我可以创建另一个请求映射来处理./groups/{id} POST

但是,我真正想知道的是...

....“为什么映射 #3 也处理 /groups/1 POST?”

“最接近匹配”的推理似乎并不成立,因为如果我删除映射#2,那么我认为映射#1会处理,但它不会,它会导致“找不到映射”异常。/groups/1 GET

我只是有点难受。


答案 1

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

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

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

但让我总结一下我是如何理解它的

  • Spring 首先检查是否至少有一个处理程序方法匹配(这可能包含漏报)
  • 然后,它创建所有真正匹配的处理程序方法的映射。
  • 然后,它按请求路径对映射进行排序:RequestSpecificMappingInfoComparator
  • 并采取第一个

排序是这样工作的:第一个在的帮助下比较路径,如果两个方法根据此相等,则相对于请求考虑其他指标(如参数数,标头数等)。RequestSpecificMappingInfoComparatorAntPathMatcher


答案 2

Spring试图找到与最接近的映射相匹配的映射。
因此,对于任何 POST 请求,为请求类型找到的唯一映射是 Mapping# 3。映射 1 或映射 2 都与您的请求类型都不匹配,因此将被忽略。也许你可以尝试删除映射#3,并看到Spring抛出运行时错误,因为它找不到匹配项!


推荐