在方法参数上使用@ModelAttribute

时间:2014-12-21 12:52:44

标签: java spring-mvc

如下link部分所述 在方法参数上使用@ModelAttribute

  

方法参数上的@ModelAttribute指示参数应该   从模型中检索。

但我观察到,即使没有使用@ModelAttribute注释UserDetail,也会正确填充userDetail。这是相关的代码段

<form:form id="userForm" action="path/userDetail" method="post" commandName="userDetail">

    @RequestMapping(value="/userDetail", method=RequestMethod.POST)
    public String processUserDetail(UserDetail userDetail, HttpServletRequest request, HttpServletResponse response, Locale locale) 
    {}

所以我的问题是spring本身填充了处理程序方法参数中存在的项目自定义对象(在本例中为userDetail) 即使没有注释@ModelAttribute。我相信@ModelAttribute在渲染视图时扮演角色,但是在提交弹出时 如果方法参数存在于模型中,则自动填充它?

2 个答案:

答案 0 :(得分:1)

即使没有注释@ModelAttribute,处理程序方法是否会解析参数?

是的,但是当发生适当的解决时, @ModelAttribute 的变化是什么。框架在参数解析过程中所做的是它接受每个参数并遍历已注册的解析器列表,并且一旦找到支持该参数的第一个解析器,它就会解析它并移动到下一个参数。

处理模型属性的解析器是ServletModelAttributeMethodProcessor。并且它被注册了两次,第一次只扫描用@ModelAttribute注释的参数,第二次作为列表中的最后一个,即使没有注释也解析参数。

您可以通过查看RequestMappingHandlerAdapter的来源检查清单和解析器的顺序。请注意ServletModelAttributeMethodProcessor的两次注册, true / false 参数确定注释是否必需

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

    // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }

    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));

    return resolvers;
}

答案 1 :(得分:0)

TLDR

当您只关心填充自己类型的实例时,无关紧要。

长版

在大多数情况下,如果添加@ModelAttribute或省略它,它就没有区别。正如@MasterSlave已经提到的,在幕后使用相同的机制。在我谈到使用@ModelAttribute的重要性之前,让我解释一下模型究竟是什么。

从正在呈现的视图来看,它是视图可以访问的数据。在您的情况下userDetail。控制器负责将所有必要的数据添加到模型中。有很多方法可以实现这一目标。 @ModelAttribute就是其中之一。

明确使用@ModelAttribute的一个用例是定义可以访问数据的密钥。 @ModelAttribute("user") UserDetail user让视图通过键user访问数据。否则它将是userDetail

在调用控制器方法之前,数据可能已经存在。也许它存储在会话中或由另一个方法生成。

意味着什么
  

应该从模型

中检索参数

但它可能存在于特定键下,例如“user”。同样,您必须通过@ModelAttribute("user")提供名称。现有数据也可以是“简单”类型,例如StringDate。在这种情况下,@ModelAttribute是从模型中检索数据所必需的。

对于由其他解析器处理的类型的参数也是如此,例如MapLocale