SpringMVC中如何处理模型数据
2016-11-06 22:13
405 查看
Spring MVC 提供了以下几种途径输出模型数据:
ModelAndView: 处理方法返回值类型为ModelAndView时, 方法体即可通过该对象添加模型数据
Map 及Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map时,处理方法返回时,Map中的数据会自动添加到模型中。
@SessionAttributes: 将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中
下面对它们依次进行介绍:
SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中。
ModelAndView设置视图的方法:
void setView(View view)
void setViewName(String viewName)
ModelAndView添加模型数据的方法:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
下面举例说明:
index.jsp:
controller:
success.jsp:
运行会成功跳转到success.jsp并显示当前时间:
通常情况下使用的都是Map类型,下面我们以Map为例说明:
index.jsp:
controller:
success.jsp:
运行程序成功跳转到success.jsp:
并且在控制台输出了:
org.springframework.validation.support.BindingAwareModelMap
这说明Spring MVC在调用方法前创建的隐含的模型对象是 BindingAwareModelMap 类型。
controller:
success.jsp:
现在,我们没有在该控制器类上标记@SessionAttributes注解,运行后跳转到success.jsp,页面显示如下:
即Map中的数据只被存放到了request域中,而没有被存放到session域中。现在,我们在该控制器类定义处添加@SessionAttributes注解:
@SessionAttributes(value=”user”,types={String.class})注解指定了属性名为user,或者类型为String的属性会被存放到session域中,现在运行程序,发现在success.jsp中既输出了request user和school,也输出了session user和school:
解决这种问题的办法是:对于对象user,我们不采取new的方式,而是使用从数据库中直接获取的方式,这样一来,user中的属性值就是原数据库中存储的属性值,那么用form表单传递过来的userName和email值更新user之后,它的id仍然为原来的值,如下图所示:
@ModelAttribute注解为我们提供了这种解决方法的实现:使用@ModelAttribute注解的方法,会在调用目标处理方法之前被调用。下面我们根据先前所说的例子来说明,修改数据库中一条user记录,其中id属性不能修改,数据库相关的操作我们仅采用模拟的方式:
index.jsp:
controller:
运行后,在控制台输出:
值得注意的是:
1、被@ModelAttribute标记的方法会在SpringMVC调用该控制器中任何目标方法之前被调用,也就是说,getUser()不仅仅只在调用testModelAttribute(User user)之前被调用,当这个控制器中任何目标方法被调用时,getUser()都会在其之前被调用。
2、getUser()中放置在map中的键值对的键“user”是testModelAttribute(User user)方法中入参类型“User”的首字母小写形式,这是一种最常用的匹配方式。其实还可以通过@ModelAttribute修饰目标方法的入参,从而使用另一种匹配方式,例如,现在我们不想把getUser()中放置在map里面的键值对的键设置为user,而是abc,即
现在,我们只要将testModelAttribute方法入参写为如下形式:
也可以正确获取到map中对应的值。
关于@ModelAttribute修饰方法和修饰入参的原理,以及工作流程,我们将在《深入理解@ModelAttribute注解的工作过程》中通过阅读SpringMVC的源码,进行更进一步的讨论。
ModelAndView: 处理方法返回值类型为ModelAndView时, 方法体即可通过该对象添加模型数据
Map 及Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map时,处理方法返回时,Map中的数据会自动添加到模型中。
@SessionAttributes: 将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性
@ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中
下面对它们依次进行介绍:
ModelAndView:
可将控制器处理方法的返回值设为ModelAndView, ModelAndView中既可存放视图信息,也可存放模型数据信息。SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中。
ModelAndView设置视图的方法:
void setView(View view)
void setViewName(String viewName)
ModelAndView添加模型数据的方法:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
下面举例说明:
index.jsp:
<a href="springmvc/testModelAndView">Test ModelAndView</a>
controller:
private static final String SUCCESS = "success"; /** * 目标方法的返回值可以是 ModelAndView 类型。 * 其中可以包含视图和模型信息 * SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中. * @return */ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ String viewName = SUCCESS; ModelAndView modelAndView = new ModelAndView(viewName); //添加模型数据到 ModelAndView 中. modelAndView.addObject("time", new Date()); return modelAndView; }
success.jsp:
time : ${requestScope.time }
运行会成功跳转到success.jsp并显示当前时间:
Map及Model:
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器(事实上这个隐含的模型对象是一个BindingAwareModelMap 类型的对象,通过后面的例子我们可以验证),如果方法的入参为Map、Model或者ModelMap 类型,Spring MVC 会将隐含模型的引用传递给这些入参(因为BindingAwareModelMap 继承或实现了Map、Model或者ModelMap)。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据,SpringMVC 也会把 Map 中数据放入到 request 域对象中。通常情况下使用的都是Map类型,下面我们以Map为例说明:
index.jsp:
<a href="springmvc/testMap">Test Map</a>
controller:
/** * 目标方法可以添加 Map 类型(实际上也可以是 Model 类型或 ModelMap 类型)的参数. * * @param map * @return */ @RequestMapping("/testMap") public String testMap(Map<String, Object> map) { System.out.println(map.getClass().getName()); map.put("names", Arrays.asList("Tom", "Jerry", "Mike")); return SUCCESS; }
success.jsp:
names: ${requestScope.names }
运行程序成功跳转到success.jsp:
并且在控制台输出了:
org.springframework.validation.support.BindingAwareModelMap
这说明Spring MVC在调用方法前创建的隐含的模型对象是 BindingAwareModelMap 类型。
@SessionAttributes:
上面介绍的两种方式,SpringMVC都是将数据存放在request域对象中,若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个@SessionAttributes注解(该注解只能放在类的上面, 而不能修饰放方法), Spring MVC 将把模型中对应的属性暂存到HttpSession中。@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中,下面举例说明(User类代码略):<a href="springmvc/testSessionAttributes">Test SessionAttributes</a>
controller:
/** * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值), * 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值) * * 注意: 该注解只能放在类的上面. 而不能修饰放方法. */ @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Map<String,Object> map){ User user = new User("Jack","123456","Jack@163.com",20); map.put("user", user); map.put("school", "HUST"); return SUCCESS; }
success.jsp:
request user : ${requestScope.user } <br><br> session user : ${sessionScope.user } <br><br> request school : ${requestScope.school } <br><br> session school : ${sessionScope.school } <br><br>
现在,我们没有在该控制器类上标记@SessionAttributes注解,运行后跳转到success.jsp,页面显示如下:
即Map中的数据只被存放到了request域中,而没有被存放到session域中。现在,我们在该控制器类定义处添加@SessionAttributes注解:
@Controller @RequestMapping("/springmvc") @SessionAttributes(value="user",types={String.class}) public class SpringMVCTest { //... }
@SessionAttributes(value=”user”,types={String.class})注解指定了属性名为user,或者类型为String的属性会被存放到session域中,现在运行程序,发现在success.jsp中既输出了request user和school,也输出了session user和school:
@ModelAttribute:
@ModelAttribute可以模拟出Struts2中Preparable拦截器的效果,想象这样一种情景:有一个User类,有id、userName、email三个属性。现在要完成一个修改操作,但是其中有一项属性不能被修改,例如id,那么只能修改两项属性,userName和email,所以从form表单传递的信息就只能有这两项,我们通常的处理方法是new一个User对象user,用form表单传递的值给user赋值,然后用user作为参数去更新信息,现在由于form表单无法传递id值,那么user.id此时就为null,便无法满足我们要求的更新操作,如下图:解决这种问题的办法是:对于对象user,我们不采取new的方式,而是使用从数据库中直接获取的方式,这样一来,user中的属性值就是原数据库中存储的属性值,那么用form表单传递过来的userName和email值更新user之后,它的id仍然为原来的值,如下图所示:
@ModelAttribute注解为我们提供了这种解决方法的实现:使用@ModelAttribute注解的方法,会在调用目标处理方法之前被调用。下面我们根据先前所说的例子来说明,修改数据库中一条user记录,其中id属性不能修改,数据库相关的操作我们仅采用模拟的方式:
index.jsp:
<!-- 模拟修改操作 1. 原始数据为: 1,Jack,Jack@163.com 2. 将username和email修改为Mike、Mike@qq.com,id不能被修改. 3. 表单回显, 模拟操作直接在表单填写对应的属性值 --> <form action="springmvc/testModelAttribute" method="Post"> username: <input type="text" name="username" value="Jack"/> <br> email: <input type="text" name="email" value="Jack@163.com"/> <br> <input type="submit" value="Submit"/> </form>
controller:
@ModelAttribute public void getUser(Map<String, Object> map) { System.out.println("modelAttribute method"); // 模拟从数据库中获取对象 User user = new User(1,"Jack", "Jack@163.com"); System.out.println("从数据库中获取一个对象: " + user); map.put("user", user); } @RequestMapping("/testModelAttribute") public String testModelAttribute(User user){ System.out.println("修改: " + user); return SUCCESS; }
运行后,在控制台输出:
值得注意的是:
1、被@ModelAttribute标记的方法会在SpringMVC调用该控制器中任何目标方法之前被调用,也就是说,getUser()不仅仅只在调用testModelAttribute(User user)之前被调用,当这个控制器中任何目标方法被调用时,getUser()都会在其之前被调用。
2、getUser()中放置在map中的键值对的键“user”是testModelAttribute(User user)方法中入参类型“User”的首字母小写形式,这是一种最常用的匹配方式。其实还可以通过@ModelAttribute修饰目标方法的入参,从而使用另一种匹配方式,例如,现在我们不想把getUser()中放置在map里面的键值对的键设置为user,而是abc,即
@ModelAttribute public void getUser(Map<String, Object> map) { System.out.println("modelAttribute method"); // 模拟从数据库中获取对象 User user = new User(1,"Jack", "Jack@163.com"); System.out.println("从数据库中获取一个对象: " + user); map.put("abc", user); }
现在,我们只要将testModelAttribute方法入参写为如下形式:
@RequestMapping("/testModelAttribute") testModelAttribute(@ModelAttribute(value="abc") User user){ System.out.println("修改: " + user); return SUCCESS; }
也可以正确获取到map中对应的值。
关于@ModelAttribute修饰方法和修饰入参的原理,以及工作流程,我们将在《深入理解@ModelAttribute注解的工作过程》中通过阅读SpringMVC的源码,进行更进一步的讨论。
相关文章推荐
- SpringMVC-05 处理模型数据
- DDD:当视图模型、领域模型和数据模型都采用了同样的类型的时候,我们该如何处理?
- springmvc之处理模型数据之ModeAndView
- SpringMVC学习笔记(7):处理模型数据(2)
- SpringMVC处理模型数据
- SpringMVC-处理模型数据
- 14. SpringMVC_处理模型数据之ModelAndView
- springmvc中的处理模型数据
- 16. SpringMVC_处理模型数据之 SessionAttributes 注解
- SpringMVC学习笔记(6):处理模型数据(1)
- WSAEventSelectI/O模型中FD_WRITE事件的处理以及如何发送数据
- springmvc 处理模型数据
- SpringMVC:学习笔记(4)——处理模型数据
- SpringMVC ------处理模型数据
- SpringMvc:处理模型数据
- springmvc之处理模型数据之map
- springMVC(7)------springMVC处理模型数据
- SpringMVC实战(四)-处理模型数据
- SpringMVC 学习笔记(四) 处理模型数据
- SpringMVC之处理数据模型