??@ModelAttribute
用于将方法参数或返回值绑定到Model属性上,并公开给Web视图。支持使用@RequestMapping
注释的Controller
类。
??注解解析
??① value
:
????待绑定到Model属性的键名称。
????默认Model属性键名称根据非限定类名从声明的属性类型(即方法参数类型或方法返回类型)推断而来:
????mypackage.OrderAddress
类型对应的键名称是orderAddress
。
????List<mypackage.OrderAddress>
类型对应的键名称是orderAddressList
。
??② name
:
????绑定的参数名称,参数值为String
类型。name
和value
可以同时使用,但两者的值需一致,否则会出现错误。
attribute 'name' and its alias 'value' are present with values of [XXX] and [XXX], but only one is permitted
??③ binding
:
????允许直接在@ModelAttribute
注释的方法参数或@ModelAttribute
注释的方法返回值上声明禁用数据绑定,这两种方法都将阻止数据绑定。
????默认情况下,binding
被设置为true
,此时将正常进行数据绑定。将binding
设置为false
,将禁用数据绑定。
??注解应用
??1) @ModelAttribute
注释方法。
??@ModelAttribute
注释方法将在Controller
中@RequestMapping
注释方法前被调用。对于@ModelAttribute
注释方法有以下几种情况:
??① @ModelAttribute
注释void返回类型方法。
??此种情况下,由于方法返回值为void类型,并不会做其他处理。因此若需要向ModeMap
中添加属性,需要通过方法参数ModelMap
来完成。
@ModelAttribute
public void modelAttributeWithVoidMethod(ModelMap modelMap) {
modelMap.addAttribute("modelAttributeWithVoidMethod","@ModelAttribute注释在void返回类型的方法上.");
}
??② @ModelAttribute
注释非void返回类型方法。
??此种情况下,①
中所使用操作ModelMap
方式仍然有效,需要通过方法参数ModelMap
来添加属性。
??同时,以返回值类型推断出的键、返回值作为键值对添加到ModelMap
中。
@ModelAttribute
public String modelAttributeWithStringMethod() {
return "@ModelAttribute注释String返回类型方法,会自动将返回值添加到ModelMap中,键根据返回类型生成.";
}
??③ @ModelAttribute
注释非void返回类型方法,并指定其name
或value
属性。
???此种情况下,①
中所使用操作ModelMap
方式仍然有效,需要通过方法参数ModelMap
来添加属性。
??同时,以@ModelAttribute
注解name
或value
属性值、返回值作为键值对添加到ModelMap
中。
@ModelAttribute("defModelAttributeName")
public String modelAttributeWithStringMethodDefName(ModelMap modelMap) {
return "@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.";
}
??④ @ModelAttribute
与@RequestMapping
注释同一方法。
??此种情况下,@ModelAttribute
与@RequestMapping
相互作用,会使@RequestMapping
表现出稍许差异。@ModelAttribute
会使得@RequestMapping
注释方法的某些类型返回值不会使用对应HandlerMethodReturnValueHandler
,而是由ModelAttributeMethodProcessor
解析。
??ModelAttributeMethodProcessor
会针对返回值与②
或③
中进行同样处理。视图名称由RequestToViewNameTranslator
根据请求/ModelAttributeWithRequestMapping.do
转换为逻辑视图ModelAttributeWithRequestMapping
。
??不受影响的返回类型包括:ModelAndView
、 Model
、 View
、ResponseBodyEmitter
、StreamingResponseBody
、HttpEntity
、HttpHeaders
、Callable
、DeferredResult
、AsyncTask
。
@ModelAttribute
@RequestMapping(value = "/ModelAttributeWithRequestMapping.do",method = RequestMethod.GET)
public String modelAttributeWithRequestMapping(ModelMap modelMap) throws Exception {
logger.info("@ModelAttribute与@RequestMapping共同作用在一个方法.");return "webannotations/ModelAttribute";
}
??2) @ModelAttribute
注释参数。
??① @ModelAttribute
注释方法参数。
??此种情况下,@ModelAttribute
注解用于ModelMap
数据映射到控制器处理方法的参数中。
@RequestMapping(value = "/ModelAttributeParameters.do",method = RequestMethod.GET)
public ModelAndView modelAttributeParameters(@ModelAttribute("defModelAttributeName") String modelAttr,ModelMap modelMap) throws Exception {
logger.info("@ModelAttribute注释方法参数,从ModelMap中取值:[key=defModelAttributeName, value=" + modelAttr + "].");return new ModelAndView("webannotations/ModelAttribute", modelMap);
}
??注解示例
??1) 建Controller
,用来演示@ModelAttribute
使用方法。
package com.arhorchin.securitit.webannotations;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;/*** @author Securitit.* @note 演示@ModelAttribute使用方法.*/
@Controller
@RequestMapping("/WebAnnotations")
public class ModelAttributeController {
/*** logger.*/private Logger logger = LoggerFactory.getLogger(ModelAttributeController.class);/*** @ModelAttribute注释* void类型返回值方法. * 需要手动ModelMap中添加数据.*/@ModelAttributepublic void modelAttributeWithVoidMethod(ModelMap modelMap) {
modelMap.addAttribute("modelAttributeWithVoidMethod","@ModelAttribute注释在void返回类型的方法上.");}/*** @ModelAttribute注释* String返回类型方法. * 会自动将返回值添加到ModelMap中,键根据返回类型生成.*/@ModelAttributepublic String modelAttributeWithStringMethod() {
return "@ModelAttribute注释String返回类型方法,会自动将返回值添加到ModelMap中,键根据返回类型生成.";}/*** @ModelAttribute注释* String类型返回值方法. * 会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.*/@ModelAttribute("defModelAttributeName")public String modelAttributeWithStringMethodDefName() {
return "@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.";}/*** ModelAttribute.do.*/@RequestMapping(value = "/ModelAttribute.do",method = RequestMethod.GET)public ModelAndView modelAttribute(ModelMap modelMap) throws Exception {
logger.info("@ModelAttribute注解测试.");return new ModelAndView("webannotations/ModelAttribute", modelMap);}/*** ModelAttribute.do.* @ModelAttribute与@RequestMapping共同注释同一方法测试.*/@ModelAttribute@RequestMapping(value = "/ModelAttributeWithRequestMapping.do",method = RequestMethod.GET)public String modelAttributeWithRequestMapping() throws Exception {
logger.info("@ModelAttribute与@RequestMapping共同作用在一个方法.");return "webannotations/ModelAttribute";}/*** ModelAttributeParameters.do.* @ModelAttribute注释参数,可以从ModelMap中取指定参数值.*/@RequestMapping(value = "/ModelAttributeParameters.do",method = RequestMethod.GET)public ModelAndView modelAttributeParameters(@ModelAttribute("defModelAttributeName") String modelAttr,ModelMap modelMap) throws Exception {
logger.info("@ModelAttribute注释方法参数,从ModelMap中取值:[key=defModelAttributeName, value=" + modelAttr + "].");return new ModelAndView("webannotations/ModelAttribute", modelMap);}}
??2) 建ModelAttributeHandlerInterceptor
,用来打印演示ModelMap
的值。
package com.arhorchin.securitit.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import com.alibaba.fastjson.JSON;/*** @author Securitit.* @note @ModelAttribute查看ModelMap测试.*/
public class ModelAttributeHandlerInterceptor implements HandlerInterceptor {
/*** logger.*/private Logger logger = LoggerFactory.getLogger(ModelAttributeHandlerInterceptor.class);/*** 在HandlerAdapter实际调用处理程序之后调用,但在DispatcherServlet呈现视图之前调用.*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {
logger.info("==============================ModelAttributeHandlerInterceptor postHandle==============================\n"+ JSON.toJSONString(modelAndView.getModelMap(), true));}}
??3) 启动服务,访问http://localhost:9199/spring-annotations/WebAnnotations/xxxxx.do
,用来查看@ModelAttribute
各种使用方法。
??① 访问http://localhost:9199/spring-annotations/WebAnnotations/ModelAttribute.do
,演示@ModelAttribute
注释单独方法。
??控制台输出:
2020-12-16 16:04:26 INFO [c.a.s.i.ModelAttributeHandlerInterceptor] ==============================ModelAttributeHandlerInterceptor postHandle==============================
{
"defModelAttributeName":"@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.","string":"@ModelAttribute注释String返回类型方法,会自动将返回值添加到ModelMap中,键根据返回类型生成.","modelAttributeWithVoidMethod":"@ModelAttribute注释在void返回类型的方法上."
}
??可以看到,@ModelAttribute
注释的modelAttributeWithVoidMethod(...)
、modelAttributeWithStringMethod()
、modelAttributeWithStringMethodDefName()
,按照解析的语义已经执行。
??② 访问http://localhost:9199/spring-annotations/WebAnnotations/ModelAttributeWithRequestMapping.do
,演示@ModelAttribute
与@RequestMapping
共同注释一个方法。
??控制台输出:
2020-12-16 16:11:37 INFO [c.a.s.i.ModelAttributeHandlerInterceptor] ==============================ModelAttributeHandlerInterceptor postHandle==============================
{
"defModelAttributeName":"@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.","modelAttributeWithVoidMethod":"@ModelAttribute注释在void返回类型的方法上.","string":"webannotations/ModelAttribute"
}
??浏览器响应:
??除了①
中所示语义外,还改变了@RequestMapping
注释方法返回值的语义,将返回值按照规则添加到ModelMap
中,视图则是由/ModelAttributeWithRequestMapping.do
来确定的。
??③ 访问http://localhost:9199/spring-annotations/WebAnnotations/ModelAttributeParameters.do
,演示@ModelAttribute
注释方法参数。
2020-12-16 16:31:23 INFO [c.a.s.i.ModelAttributeHandlerInterceptor] ==============================ModelAttributeHandlerInterceptor postHandle==============================
{
"defModelAttributeName":"@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.","modelAttributeWithVoidMethod":"@ModelAttribute注释在void返回类型的方法上.","string":"@ModelAttribute注释String返回类型方法,会自动将返回值添加到ModelMap中,键根据返回类型生成."
}
2020-12-16 16:31:41 INFO [c.a.s.w.ModelAttributeController] @ModelAttribute注释方法参数,从ModelMap中取值:[key=defModelAttributeName, value=@ModelAttribute注释String类型返回值方法,会自动将返回值添加到ModelMap中,键是@ModelAttribute的name或value属性值.].
??可以看到,@ModelAttribute
注释方法将从ModelMap
中获取值,绑定到方法参数上。
??总结
??@ModelAttribute
主要针对ModelMap
进行操作,对于传统的、前后端未分离的应用来说,用处还是很大的。
??源码解析基于spring-framework-5.0.5.RELEASE
版本源码。
??若文中存在错误和不足,欢迎指正!