Spring MVC 提供了以下几种途径输出模型数据:
一、输出模型
– 1、ModelAndView:
处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
//后台数据
Public ModelAndView test(){
String viewName = "succeess";//需要跳转的页面名
ModelAndView mv = new ModelAndView(viewName);
Mv.addObject("time",new Date());
Return mv;
}
//前端页面
${requestScope.time}
添加进去的Object对象是存放在request里面
– 2、Map 及 Model:
入参为 org.springframework.ui.Model、org.springframework.ui. ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
Public String test(Map<String,Object> map){ //这个map的实现是BindingAwareModelMap
map.put("time",new Date());
Return "success";
}
– 3、@SessionAttributes:
将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
– 4、@ModelAttribute:
方法入参标注该注解后, 入参的对象 就会放到数据模型中
该注解的作用是每次调用控制层的方法时都会先调用该方法进行一定的数据处理,然后反馈给原本要调用的控制层方法
@ModelAttribute注解的方法有两种,一种无返回值,一种有返回值,方法的可以用@RequestParam注解来获取请求的参数,如果不获取参数,可以不用此注解
1)无返回值,用Map中的对象放入ImpliciteModel中,key就是map中存储的key.
@ModelAttribute
public void setUser(@RequestParam(value="name",required=false) String name, Map<String,Object> map)
{
Address ad=new Address();
ad.setCity("beijing");
ad.setProvince("china");
User u=new User();
u.setAge(15);
u.setAddress(ad);
if(name.equals("xp")){
u.setWork("huajia");
}
else {
u.setWork("gongchengshi");
}
map.put("user", u);
System.out.println(u);
}
2)有返回值 把返回值对象放入ImpliciteModel中,key就是ModelAttribute定义的key:"user"
@ModelAttribute(value="user")
public User getUser() {
User user = new User();
user.setId(2);
System.out.println(user);
return user;
}
@RequestMapping("/helloword")
public String helloworld(@ModelAttribute User user) { //若没有指定@ModelAttribute(value="**"),则以类名第一个字母小写获取
System.out.println(user + "...000");
return "success";
}
总结: @ModelAttribute("user")指定key为"user"时,若方法有返回值,则返回值会以指定的key,放入ImpliciteModel中;若方法没有返回值,但是方法中有相同key的map,则存入ImpliciteModel中key的为map中存的对象,若没有相同key的map,则存入ImpliciteModel中key对应的对象为null.若方法有返回值且方法中也有相同key的map,则以map对象优先。@ModelAttribute没有指定key时,只能用Map将对象存入ImpliciteModel中。
ImpliciteModel中的对象,可以认同为Request域中对象。
二、 POJO入参过程流程解释
1,检查implicite中是否存在相同key(默认为pojo类名小写,可以用@modelattribute指定)的值,有则传入,并用请求的参数值替换对应的值。
2,若implicite中没有,则检查sessionattribute中是否相同key的值,有则同一,没有则抛异常(可以通过配置,避免异常)。
3,若1、2中都没有,则通过反射创建对象,并用请求的参数值替换对应的值。最后再把对象存入implicite中。
被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用
– SessionAttribute注解与ModelAttribute注解引起的异常:
没有使用@ModelAttribute修饰的方法,且在某个目标方法入参使用了@SessionAttribute注解value同名的实体对象,会抛出异常。
原因:
if (implicitModel.containsKey(name)) {
bindObject = implicitModel.get(name);
} else if (this.methodResolver.isSessionAttribute(name, paramType)) {
bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
if (bindObject == null) {
raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
}
}
在绑定参数前,此时Model中没有值,然后会进入另一个分支,就会抛出异常。
解决办法:
1. @SesionAttribute和方法入参处使用不同名的value值
2. 添加@ModelAttribute修饰的方法,方法内将实体放入ModelMap中。