本文源码基于SpringMVC 5.2.7
@ModelAttribute
@ModelAttribute可以用在方法上,也可以用在参数上。当它用在方法上时候,SpringMVC会将其返回值绑定到model的属性上;当它用在参数上时候,SpringMVC会从model取出对应的属性传给该参数。
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean binding() default true;
}
- name() : 表示model中的属性名
- binding() : 表示在参数解析时是否需要执行该属性的databind操作,默认是true
@ModelAttribute必须用在@Controller或者@ControllerAdvice注解的类上,否则SpringMVC收集不到。
用在方法上
@ModelAttribute用在方法上有2个作用:
1 绑定返回值到model的属性上,属性名或由@ModelAttribute,或根据方法返回类型生成。 例如:mypackage.OrderAddress 生成的名字是 orderAddress;List<mypackage.OrderAddress>生成的名字是orderAddressList。
2 如果@ModelAttribute所注解的方法上没有@RequestMapping注解,那么该方法将在请求的处理方法前执行。除了返回值将绑到model上,开发者还可以对model进行一些处理
示例一 没有@RequestMapping,不指定name
定义一个测试类
public class TestModelAttribute {
private String testName;
private String testSource;
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getTestSource() {
return testSource;
}
public void setTestSource(String testSource) {
this.testSource = testSource;
}
}
添加一个@ModuleAttribute注解的方法,@ModuleAttribute没有指定name,预期结果是model中增加一个属性,属性名根据TestModelAttribute类名生成得到
@ControllerAdvice
public class DemoControllerAdvice {
@ModelAttribute
public TestModelAttribute testInitModel() {
TestModelAttribute result = new TestModelAttribute();
result.setTestName("test");
result.setTestSource("h5");
return result;
}
}
运行结果:model里面增加了属性名为"testModelAttribute"的属性
示例二 没有@RequestMapping,通过ModelMap直接向model添加更多的属性
@ControllerAdvice
public class DemoControllerAdvice {
@ModelAttribute
public void testInitModel(ModelMap model) {
model.put("test1", "value1");
model.put("test2", "value2");
model.put("test3", "value3");
}
}
用在参数上
@ModelAttribute用在参数上主要用来进行参数解析,@ModelAttribute对应的参数解析器org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor。过程是将model中name对应的对象赋值给参数,如果该name没有被设置"bindingDisabled",那么将从reques取得数据绑定到参数对象中。
@ModelAttribute在参数上非必须,即便没有@ModelAttribute注解,只要参数类型是非简单类型,SpringMVC的参数解析器ServletModelAttributeMethodProcessor也会执行上述操作,只不过此时属性name就只能根据参数类型生成。
示例一 有注解@ModelAttribute,并指定name
先在testInitModel中指定name
@ModelAttribute(name = "test")
public TestModelAttribute testInitModel() {
TestModelAttribute result = new TestModelAttribute();
result.setTestName("testName");
result.setTestSource("H5");
return result;
}
在请求的处理方法中增加参数TestModelAttribute,添加@ModelAttribute注解并指定name
@Controller
@RequestMapping("/focuse")
public class DemoController {
@ResponseBody
@RequestMapping("hello")
public String hello(@ModelAttribute(name = "test") TestModelAttribute input) {
return "hello world!";
}
}
运行结果-input值来源于model中属性名为"test"的对象
示例二 没有注解@ModelAttribute,请求指定参数testName
请求的处理方法上增加TestModelAttribute参数,但是没有注解@ModelAttribute
@Controller
@RequestMapping("/focuse")
public class DemoController {
@ResponseBody
@RequestMapping("hello")
public String hello(TestModelAttribute input) {
return "hello world!";
}
}
请求指定参数testName=WithoutAnnotation:127.0.0.1:8080/focuse/hello?testName=WithoutAnnotation
总结
在方法上使用场景
场景 | 方法是否有@RequestMapping | 是否指定name | 效果 |
方法上 | 没有 | 指定 | 在调用请求处理方法前,往model添加指定name的属性, 并根据注解@ModelAttribute的binding属性设置该属性对应的参数是否需要绑定数据 |
没有 | 不指定 | 在调用请求处理方法前,往model添加属性,属性的名字根据方法返回类型生成, 并根据注解@ModelAttribute的binding属性设置该属性是否需要绑定数据 | |
有 | 指定 | 在调用请求处理方法之后,往model添加指定name的属性, 并根据注解@ModelAttribute的binding属性设置该属性是否需要绑定数据 | |
有 | 不指定 | 在调用请求处理方法之后,往model添加属性,属性的名字根据方法返回类型生成, 并根据注解@ModelAttribute的binding属性设置该属性是否需要绑定数据 |
在参数上使用场景
场景 | 是否有注解@ModelAttribute | 是否指定name | 效果 |
参数上 | 没有 | / | 1. 从model取出属性赋值给该参数,属性的名字根据参数类型生成,如果model中没有则根据参数类型创建对象。 2. 根据model中该属性的绑定设置确定是否对参数的对象执行数据绑定
|
有 | 指定 | 1. 从model取出属性赋值给该参数,属性的名字根据参数类型生成,如果model中没有则根据参数类型创建对象。 2. 根据注解@ModelAttribute的binding属性设置是否需要绑定数据 3. 根据model中该属性的绑定设置确定是否对参数的对象执行数据绑定 | |
有 | 不指定 | 1. 从model取出属性赋值给该参数,属性的名字根据参数类型生成,如果model中没有则根据参数类型创建对象。 2. 根据注解@ModelAttribute的binding属性设置是否需要绑定数据 3. 根据model中该属性的绑定设置确定是否对参数的对象执行数据绑定 |
上一篇 参数解析器HandlerMethodArgumentResolver
下一篇 返回处理器HandlerMethodReturnValueHandler
再下一篇 异步请求WebAsyncManager