- SpringMVC提供了以下几种途径输出模型数据:
- ModelAndView
- Map、Model
- @SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间共享这个属性。
- @ModelAttribute:将入参的对象放到数据模型中。
1、ModelAndView
package com.xianhuii; import com.xianhuii.entities.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date; @Controller @RequestMapping("/springmvc") public class RequestMappingTest01 { 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; } }
2、Map、Model
import java.util.Map; @Controller @RequestMapping("/springmvc") public class RequestMappingTest01 { private static final String SUCCESS = "success"; /** * 目标方法可以添加Map类型(实际上也可以是Model、ModelMap类型)对象 * @param map * @return */ @RequestMapping("/testMap") public String testMap(Map<String, Object> map) { map.put("names", Arrays.asList("Tom", "Jerry", "Mike")); return SUCCESS; } }
3、@SessionAttributes
只能放在Controller类上。
源码:
package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface SessionAttributes { @AliasFor("names") String[] value() default {}; @AliasFor("value") String[] names() default {}; Class<?>[] types() default {}; }
示例:
package com.xianhuii; import com.xianhuii.entities.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.Date; import java.util.Map; @SessionAttributes(value = {"user"}, types = {String.class}) @Controller @RequestMapping("/springmvc") public class RequestMappingTest01 { private static final String SUCCESS = "success"; /** * @SessionAttributes * 可以通过属性名指定需要放到会话中的属性(value) * 还可以通过模型属性的对象类型指定那些模型属性需要放到会话中(types) * @param map * @return */ @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Map<String, Object> map) { User user = new User("Tom", "123456", "tom@qq.com", 18); map.put("user", user); map.put("school", "tj"); return SUCCESS; } }
4、@ModelAttribute
前端:
<%--模拟修改操作 1、原始数据为:1, Tom, 123456, tom@qq.com, 18 2、密码不能被修改。 3、表单回显,模拟操作直接在表单填写对应的属性值 --%> <form action="/springmvc/testModelAttribute" method="post"> <input type="hidden" name="id", value="1"> <p>username: <input type="text" name="username" value="Tom"></p> <p>email: <input type="text" name="email" value="tom@qq.com"></p> <p>age: <input type="text" name="age" value="18"></p> <p><input type="submit" value="Submit"></p> </form>
Controller:
package com.xianhuii; import com.xianhuii.entities.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.Date; import java.util.Map; //@SessionAttributes(value = {"user"}, types = {String.class}) @Controller @RequestMapping("/springmvc") public class RequestMappingTest01 { private static final String SUCCESS = "success"; /** * 执行流程: * 1、执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放入到Map中,键为:user * 2、SpringMVC从Map中取出User对象,并把表单的请求参数赋给该User对象的对应属性。 * 3、SpringMVC把上述对象传入目标方法的参数。 * * 注意:在@ModelAttribute修饰的方法中,放入到Map时的键,需要和目标方法入参类型的第一个字母小写的字符串一致。 * * 源码分析的流程: * 1、调用@ModelAttribute修饰的方法。把@ModelAttribute方法中Map中的数据放在了implicitModel中。 * 2、解析请求处理器的目标参数。该目标参数来自于WebDataBinder对象的target属性。 * 2.1、创建WebDataBinder对象: * ①确定objectName属性:若传入的attrName为"",则objectName为类名第一个字母小写。 * 注意:若目标方法的POJO属性使用了@ModelAttribute修饰,则attrName值即为@ModelAttribute的value属性值。 * ②确定target属性:在implicitModel中查找attrName对应的属性值 * - 如果存在,ok; * - 如果不存在,则验证当前Handler是否使用了@SessionAttributes进行修饰, * 若使用了则尝试从Session中获取attrName锁对应的属性值。若session中没有对应的值,则抛出异常; * - 若Handler没有使用@SessionAttributes进行修饰,或@SessionAttributes中没有使用value值指定 * 的key和attrName,则通过反射创建POJO对象。 * 2.2、SpringMVC把表单的请求参数赋给了WebDataBinder的target对应的属性。 * 2.3、SpringMVC会把WebDataBinder的attrName和target给implicitModel,进而传到request域对象中。 * 2.4、把WebDataBinder的target作为参数传递给目标方法的入参。 * * 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 * 所对应的值,若存在则直接传入到目标方法的入参中;若不存在,则将抛出异常。 * 4、若Handler没有表示@SessionAttributes,或@SessionAttributes的value不包含key,则会通过反射来创 * 建POJO类型的参数,传入为目标方法的参数。 * 5、SpringMVC会把key和POJO类型的对象保存到implicitModel中,进而会保存到request中。 * @param user * @return */ @RequestMapping("/testModelAttribute") public String testModelAttribute(User user) { System.out.println("修改" + user); return SUCCESS; } /** * 1、有@ModelAttribute标记的方***在每个目标方法执行之前被SpringMVC调用。 * 2、@ModelAttribute也可以用来修饰目标方法POJO类型的入参,其value属性值有如下的作用: * 2.1、SpringMVC会使用value属性值在implicitModel中查找对应的对象,若存在则会直接传入到目标方法的入参中。 * 2.2、SpringMVC会以value为key,POJO类型的对象为value,存入到request中。 * @param id * @param map */ @ModelAttribute public void getUser(@RequestParam(value = "id", required = false) Integer id, Map<String, Object> map) { if (id != null) { // 模拟从数据库中获取对象 User user = new User(1, "Tom", "123456", "tom@qq.com", 18); map.put("user", user); } }