Spring MVC 提供了以下几种途径输出模型数据:
ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
Map 及 Model: 入参为 – org.springframework.ui.Model、org.springframework.ui. ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
@SessionAttributes: 将模型中的某个属性暂存到 – HttpSession 中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象– 就会放到数据模型中
一、ModelAndView的用法
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
设置视图:
void setView(View view)– void setViewName(String viewName)
/**
* 目标方法中返回值可以是ModelAndView类型
* 其中可以包含视图和模型信息
* SpringMvc会把ModelAndView的model中数据放入到request域对象中
*/
@RequestMapping("/testModelAndView")
private ModelAndView testModelAndView(){
String viewName=SUCCESS;
ModelAndView modelAndView=new ModelAndView(viewName);
modelAndView.addObject("time", new Date());
return modelAndView;
}
二、Map及Model的用法
Spring MVC在内部使用了一个org.springframework.ui.Model 接口存储模型数据
具体步骤:
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
如果方法的入参为 Map或Model类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向
模型中添加新的属性数据
/**
* 目标方法可以添加Map类型(实际上也可以用Model类型ModelMap类型)的参数
*/
@RequestMapping("/testMap")
private String testMap(Map<String, Object> map){
map.put("name", Arrays.asList("tom","tim","xiaoming"));
System.out.println(map);
return SUCCESS;
}
三、@SessionAttributes的用法
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC将在模型中对应的属性暂存到HttpSession中。
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中
@SessionAttributes(types=User.class)会将隐含模型中所有类型为 User.class 的属性添加到会话中。
@SessionAttributes(value={“user1”, “user2”})
@SessionAttributes(types={User.class, Dept.class})
@SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@RequestMapping("/testSessionAttribute")
private String testSessionAttribute(Map<String,Object> map){
UserInfo userInfo=new UserInfo("xiaomei", "a", 22, "xiaomei@qq.com");
map.put("userInfo", userInfo);
map.put("school", "school");
return SUCCESS;
}
注意:@SessionAttributes(value={"userInfo"},types={String.class})必须放置在类外,不能放在里面,然后value中的值对应的是map里面的值,type表示放入session的类型
结果测试代码:
request userInfo:${requestScope.userInfo}
<br>
session userInfo: ${sessionScope.userInfo}
<br>
request school:${requestScope.school}
<br>
session school: ${sessionScope.school}
四、@ModelAttribute的用法
这个方法主要用于那些要修改表信息的部分字段,且最后没有被修改的字段保持原样输出
/**
* 1.有@ModelAttribute标记的方法,会在每个目标方法执行之前被springmvc调用
* 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
* 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中.
*/
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false)Integer id,Map<String,Object> map){
if(id!=null){
UserInfo userInfo = new UserInfo(1, "tom", "123456", 22, "ymf@qq.com");
System.out.println("模拟数据库传过来的对象值:"+userInfo);
map.put("userInfo", userInfo);
}
}
/**
* 运行流程
* 1.执行@ModelAttribute注释的方法:取出数据库中的对象,把对象放入Map中:map.put("userInfo", userInfo);键为userInfo
* 2.springmvc从Map中取出UserInfo对象,并把表单的请求参数赋给该User对象的对应属性
* 3.springmvc把上述对象传入目标方法的参数
* 注意:在@ModelAttribute修饰的方法中,放到Map时的键需要和目标方法入参类型第一个字母小写的字符串一致。
* SpringMVC 确定目标方法 POJO 类型入参的过程
* 1. 确定一个 key:
* 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
* 2). 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值.
* 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
* 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到.
* 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰,
* 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所
* 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常.
* 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则
* 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
* 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
* 源代码分析的流程
* 1.调用@ModelAttribute注释修饰的方法,实际上把@ModelAttribute方法中的Map中的数据放在了iMplicitModel中
* 2.解析请求参数处理器的目标参数,实际上该目标参数来自于webdatabinder对象的target属性
* 1).创建webdatabinder对象:
* a.确定objectName属性:若传入的attrname属性值为"",则objectName为类名第一个字母小写
* 注意:attrName.若目标方法的pojo属性使用了@ModelAttribute来修饰,则attrName就是ModelAttribute的value属性值
*
* 2).确定target属性:
* a.在implicitModel中查找attrName对应的属性值,若存在,ok
* b.若不存在:则验证当前Handler是否使用了@sessionAttributes进行修饰,若使用了,则尝试从session中
* 获取attrName所对应的属性值。若session中没有对应的属性值,则抛出异常
* c.若Handler没有使用@sessionAttributes进行修饰,或者@sessionAttributes中没有value值
* 指定的key和attrName相匹配 ,则通过反射创建了pojo对象
*
* 3).springmvc把表单的请求参数付给了WebDataBinder的target对应的属性
* 4).springmvc会把WebDataBinder的attrName和target给到implicitModel
* 5).把WebDataBinder的target作为参数传递给目标方法的入参
*/
@RequestMapping("/testModelAttribute")
private String testModelAttribute(UserInfo userInfo){
System.out.println("修改"+userInfo);
return SUCCESS;
}
五、由@SessionAttributes引发的异常
如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用请求消
息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常
那我们如何避免@SessionAttributes引发的异常呢?
1、加一个getUser方法
2、使@SessionAttributes("xxx")中的xxx和下面方法中的@ModelAttribute的value属性值不一样就行了
@RequestMapping("/testModelAttribute")
private String testModelAttribute(@ModelAttribute("abc")UserInfo userInfo){
System.out.println("修改"+userInfo);
return SUCCESS;
}
ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
Map 及 Model: 入参为 – org.springframework.ui.Model、org.springframework.ui. ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
@SessionAttributes: 将模型中的某个属性暂存到 – HttpSession 中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象– 就会放到数据模型中
一、ModelAndView的用法
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
设置视图:
void setView(View view)– void setViewName(String viewName)
/**
* 目标方法中返回值可以是ModelAndView类型
* 其中可以包含视图和模型信息
* SpringMvc会把ModelAndView的model中数据放入到request域对象中
*/
@RequestMapping("/testModelAndView")
private ModelAndView testModelAndView(){
String viewName=SUCCESS;
ModelAndView modelAndView=new ModelAndView(viewName);
modelAndView.addObject("time", new Date());
return modelAndView;
}
二、Map及Model的用法
Spring MVC在内部使用了一个org.springframework.ui.Model 接口存储模型数据
具体步骤:
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
如果方法的入参为 Map或Model类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向
模型中添加新的属性数据
/**
* 目标方法可以添加Map类型(实际上也可以用Model类型ModelMap类型)的参数
*/
@RequestMapping("/testMap")
private String testMap(Map<String, Object> map){
map.put("name", Arrays.asList("tom","tim","xiaoming"));
System.out.println(map);
return SUCCESS;
}
三、@SessionAttributes的用法
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC将在模型中对应的属性暂存到HttpSession中。
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中
@SessionAttributes(types=User.class)会将隐含模型中所有类型为 User.class 的属性添加到会话中。
@SessionAttributes(value={“user1”, “user2”})
@SessionAttributes(types={User.class, Dept.class})
@SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@RequestMapping("/testSessionAttribute")
private String testSessionAttribute(Map<String,Object> map){
UserInfo userInfo=new UserInfo("xiaomei", "a", 22, "xiaomei@qq.com");
map.put("userInfo", userInfo);
map.put("school", "school");
return SUCCESS;
}
注意:@SessionAttributes(value={"userInfo"},types={String.class})必须放置在类外,不能放在里面,然后value中的值对应的是map里面的值,type表示放入session的类型
结果测试代码:
request userInfo:${requestScope.userInfo}
<br>
session userInfo: ${sessionScope.userInfo}
<br>
request school:${requestScope.school}
<br>
session school: ${sessionScope.school}
四、@ModelAttribute的用法
这个方法主要用于那些要修改表信息的部分字段,且最后没有被修改的字段保持原样输出
/**
* 1.有@ModelAttribute标记的方法,会在每个目标方法执行之前被springmvc调用
* 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
* 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中.
*/
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false)Integer id,Map<String,Object> map){
if(id!=null){
UserInfo userInfo = new UserInfo(1, "tom", "123456", 22, "ymf@qq.com");
System.out.println("模拟数据库传过来的对象值:"+userInfo);
map.put("userInfo", userInfo);
}
}
/**
* 运行流程
* 1.执行@ModelAttribute注释的方法:取出数据库中的对象,把对象放入Map中:map.put("userInfo", userInfo);键为userInfo
* 2.springmvc从Map中取出UserInfo对象,并把表单的请求参数赋给该User对象的对应属性
* 3.springmvc把上述对象传入目标方法的参数
* 注意:在@ModelAttribute修饰的方法中,放到Map时的键需要和目标方法入参类型第一个字母小写的字符串一致。
* SpringMVC 确定目标方法 POJO 类型入参的过程
* 1. 确定一个 key:
* 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
* 2). 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值.
* 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
* 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到.
* 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰,
* 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所
* 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常.
* 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则
* 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
* 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
* 源代码分析的流程
* 1.调用@ModelAttribute注释修饰的方法,实际上把@ModelAttribute方法中的Map中的数据放在了iMplicitModel中
* 2.解析请求参数处理器的目标参数,实际上该目标参数来自于webdatabinder对象的target属性
* 1).创建webdatabinder对象:
* a.确定objectName属性:若传入的attrname属性值为"",则objectName为类名第一个字母小写
* 注意:attrName.若目标方法的pojo属性使用了@ModelAttribute来修饰,则attrName就是ModelAttribute的value属性值
*
* 2).确定target属性:
* a.在implicitModel中查找attrName对应的属性值,若存在,ok
* b.若不存在:则验证当前Handler是否使用了@sessionAttributes进行修饰,若使用了,则尝试从session中
* 获取attrName所对应的属性值。若session中没有对应的属性值,则抛出异常
* c.若Handler没有使用@sessionAttributes进行修饰,或者@sessionAttributes中没有value值
* 指定的key和attrName相匹配 ,则通过反射创建了pojo对象
*
* 3).springmvc把表单的请求参数付给了WebDataBinder的target对应的属性
* 4).springmvc会把WebDataBinder的attrName和target给到implicitModel
* 5).把WebDataBinder的target作为参数传递给目标方法的入参
*/
@RequestMapping("/testModelAttribute")
private String testModelAttribute(UserInfo userInfo){
System.out.println("修改"+userInfo);
return SUCCESS;
}
五、由@SessionAttributes引发的异常
如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用请求消
息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常
那我们如何避免@SessionAttributes引发的异常呢?
1、加一个getUser方法
2、使@SessionAttributes("xxx")中的xxx和下面方法中的@ModelAttribute的value属性值不一样就行了
@RequestMapping("/testModelAttribute")
private String testModelAttribute(@ModelAttribute("abc")UserInfo userInfo){
System.out.println("修改"+userInfo);
return SUCCESS;
}