当前位置: 代码迷 >> 综合 >> Spring 注解面面通 之 @ModelAttribute 模型属性绑定全解
  详细解决方案

Spring 注解面面通 之 @ModelAttribute 模型属性绑定全解

热度:21   发布时间:2024-01-17 01:00:17.0

??@ModelAttribute用于将方法参数或返回值绑定到Model属性上,并公开给Web视图。支持使用@RequestMapping注释的Controller类。

??注解解析

??① value

????待绑定到Model属性的键名称。

????默认Model属性键名称根据非限定类名从声明的属性类型(即方法参数类型或方法返回类型)推断而来:

????mypackage.OrderAddress类型对应的键名称是orderAddress

????List<mypackage.OrderAddress>类型对应的键名称是orderAddressList

??② name

????绑定的参数名称,参数值为String类型。namevalue可以同时使用,但两者的值需一致,否则会出现错误。

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返回类型方法,并指定其namevalue属性。

???此种情况下,中所使用操作ModelMap方式仍然有效,需要通过方法参数ModelMap来添加属性。

??同时,以@ModelAttribute注解namevalue属性值、返回值作为键值对添加到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

??不受影响的返回类型包括:ModelAndViewModelViewResponseBodyEmitterStreamingResponseBodyHttpEntityHttpHeadersCallableDeferredResultAsyncTask

@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版本源码。

??若文中存在错误和不足,欢迎指正!

  相关解决方案