ModelAttribute
@ModelAttribute注解用于将请求的参数绑定到Model对象中,方便在前台回显
- 在方法定义上使用@ModelAttribute注解:SpringMVC在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribue的方法
- 在方法入参前使用@ModelAttribute注解:
@ModelAttribute注解一个方法
@ModelAttribute("student")
public Student getStudent() {
Student student = new Student("Reyco",21);
return student;
}
- 如果方法返回pojo对象,那么可以不用在@ModelAttribute中加上value属性,其值就是返回类型的首字母小写,即Student–>student
- 如果方法没有返回值,那么可以在方法形参中加上一个Model类型,在方法体内执行addAttribute
- 如果方法返回普通类型,那么可以在注解里面加上value属性,指定model中的key值
在调用控制器处理方法前如果有方法使用了@ModelAttribute注解,那么每个请求都会先请求这个方法,然后再调用控制器处理方法,假设请求A方法,则会先请求标注了@ModelAttribute的getStudent()方法,执行此方法会将student以(“student”,student)的形式添加到Model中,然后再执行A方法
@ModelAttribute注解方法的形参
在控制器的处理器方法参数上标注@ModelAttribute可以访问模型中的属性,如果不存在这个模型,则会自动将其实例化,产生一个新的模型,如果方法参数为pojo类在不是有@ModelAttribute时,默认在Model中查找pojo类首字母小写对象并传入。
@RequestMapping("/test/sessionAttribute")
public String ModelTest(Map<String,Object> map,@ModelAttribute("student")Student student,Integer id){
map.put("time",new Date());
student.setAge(25);
map.put("id",id);
return SUCCESS;
}
- SpringMVC会自动将pojo类型添加到Model中,key为该pojo的类名首字母小写,即使没有@ModelAttribute,仍然会将student写到Model中,类似map.put(“student”,student),如果想要改变key值,就必须使用@ModelAttribute(value=key)
- 对于普通类型,SpirngMVC并不会自动注入到Model中,必须收到编写map.put(),栗子中id为Integer为普通类型,若想要注入Model中,就必须使用@ModelAttribute(value=key),或者在方法体内使用map.put(“xxx”,id)
@ModelAttribute和@RequestMapping方法作用于同一个方法
@RequestMapping("/login")
@ModelAttribute("loginname")
public String login(){
return "admin";
}
- 当使用@RequestMapping和@ModelAtribute一起注解一个方法的时候,方法的返回值是会将加入到Model中的
- 视图名应该是@RequestMapping的value的值,这里就是login
- 请求的时候也是按照@RequestMapping的value进行请求
ModelAttribute原理剖析
@ModelAttribute修饰方法
- 调用@ModelAttribute注解修饰的方法,实际上把标注了@ModelAttribute方法中Map的数据放在了implicitModel中
- 解析请求处理器方法(非@ModelAttribute修饰的方法)的目标参数,实际上该目标参数来自WebDataBinder对象的target属性
- 创建WebDataBinder对象:
- 确定objectName属性:若传入的attrName属性值为“”,则objectName为类名第一个字母小写注意:若目标方法的POJO属性使用了@ModelAttribute进行修饰,则attrName值即为@ModelAttribute设置的属性值
- 确定target属性:在implicitModel中查找attrName对于的属性值,若存在,ok;若不存在:则验证当前Handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值,若Session中没有对于的属性值(抛出异常的情况是:@SessionAttributes设置了和attrName对应的key,但是这个key没有value),则抛出异常;若Handler没有使用@SessionAttributes进行修饰或@SessionAttributes中找不到和attrName相匹配的key,则通过反射创建POJO对象
- SpringMVC将表单的请求参数赋给了WebDataBinder中的target对应的属性
- SpringMVC将WebDataBinder的attrName和target给到implicitModel
- 将WebDataBinder的target作为参数传递给目标方法的入参
- 创建WebDataBinder对象:
@ModelAttribute修饰POJO参数
- SpringMVC会使用value属性值在implicitModel中查找对应的对象,若存在则直接传入到目标方法的入参中
- SpringMVC将@ModelAttribute的value作为key,POJO类型的对象作为value,存入到request域中
@SessionAttribute和@ModelAttributes引发异常
当使用@ModelAttribute注解时,会取@ModelAttribute的value值,若@ModelAttribute的value值是空串(即没有配置@ModelAttribute的value属性),则会将当前用@ModelAttribute修饰的方法的Bean参数或直接用@ModelAttribute修饰的Bean 的首字母小写Bean的名字作为attrName.
接下来会判断,如果request(Map)的键中包含了attrName,则取键值为attrName的值赋给Bean,若没有包含,会判断当前Handler是否使用了@SessionAttribute。若使用了则会判断@SessionAttribute的value或names中是否包含了attrName,若有,则将@SessionAttribute名为attrName的值作为attrName的值,若@SessionAttribute的values或names中包含但是没有相应的值,则会抛出 异常。若request(Map)和@SessionAttribute都不包含arrtName则利用反射新创建一个attrName的Bean