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

lim*_*imc 32 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) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,此页面具有以下功能: -

  • 用户访问主页面(/groups GET).
  • 用户创建新组(/groups POST)或选择特定组(/groups/1 GET).
  • 用户编辑现有组(/groups/1 POST).

我理解这两个GET请求映射是如何工作的.映射#2已定义,否则(/groups/1 GET)将导致"未找到映射"异常.

我在这里想要理解的是为什么映射#3处理(/groups POST)和(/groups/1 POST)?/groups POST因为请求映射与URI匹配,所以它应该在这里处理().为什么(/groups/1 POST)不会导致在此处抛出"未找到映射"异常?事实上,似乎任何带有以/ groups(ex :)开头的URI的POST /groups/bla/1 POST也将通过映射#3来处理.

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

澄清

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

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

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

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

我只是有点难过.

Ral*_*lph 19

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

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

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

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

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

排序以这种方式工作:第RequestSpecificMappingInfoComparator一个将路径与a的帮助进行比较AntPathMatcher,如果两个方法根据此相等,那么其他度量(如参数数量,标题数量等)将被考虑在内.请求.

  • 哇...我查看`resolveHandlerMethod(...)`,谈谈超高的圈复杂度代码,我在第n次嵌套if语句后丢失了.我阅读了关于订单列表的`RequestSpecificMappingInfoComparator`上的javadoc.我很好奇为什么他们对GET和POST方法的行为不一样.换句话说,如果我删除映射#2,为什么映射#1不处理`/ groups/1 GET`,而是Spring抛出异常...... (4认同)