ModuleAndView
- 注意:ModelAndView的类型为:org.springframework.web.servlet.ModelAndView;
- 示例使用ModuleAndView处理模型数据
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView(viewName);
modelAndView.addObject("info", "你好");
return modelAndView;
}
- 使用ModuleAndView实际上会将数据使用request.setAttribute()方法保存在请求域之中.因此可以在页面中使用EL表达式获取请求属性.
- 跳转的页面
<body>
<h1>${info}</h1>
</body>
Map处理模型数据
- 示例:
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("time",new Date());
map.put("tom","xiemaoshu");
return SUCCESS;
}
- SpringMVC会将数据存储到 Request范围域之中,在页面中可以使用 EL表达式取出数据
<h1>${time}</h1>
<h1>${tom}</h1>
- 执行效果
@SessionAttributes
- @SessionAttribute注解使用示例
//将名称为"user"的属性添加到Session属性之中,也将String类型的属性添加到Session属性之中
@SessionAttributes(types = {User.class,String.class},value = {"user"})
@Controller
public class HelloWorld {
@RequestMapping("/testSessionAttribute")
public String testSessionAttribute(Map<String,Object> map){
User user = new User();
user.setUid(11);
user.setUname("xiemaoshu");
user.setPassword("xiemaoshu20190309xms");
map.put("user",user);
map.put("time",new Date());
return SUCCESS;
}
- 显示页面
<h1>${user}</h1>
<h1>${time}</h1>
- 效果
@ModuleAttribute注解
遇到的问题?
- 如果此时要进行对数据库中的一个数据进行修改操作,但是要求:某一个字段的内容不允许被修改.例如:修改一个用户的数据"User",用户数据中的创建时间与密码信息是不允许被修改的.如果从表单中直接收要修改的数据,那么在操作方法中往往需要提供一个User类实例化对象,那么这个User类实例化对象中,"创建时间"和"密码"字段只能够是"null"空,如何能够放置出现null的情况?
实现的思路有两种:
- 由表单填入修改数据,但是不提供"创建时间"和"密码"的修改操作,将用户的创建时间和密码信息由隐藏域保存起来,接着再调用方法中new一个实例化对象,将修改数据保存到新的实例化对象之中.
- 这样做有一个缺点就是:重要的信息不适合放在隐藏域中,况且,如果不能够修改的字段比较多的话,需要设置多个隐藏域.
- 先从数据库中读取出要修改的用户信息,而后只提供要修改的数据操作
使用@ModuleAttribute解决
- 模拟一个数据修改操作
- 修改页面表单
<body>
<%--
模拟一个数据修改操作
原始数据为:
uid=1
password=12345
uname=xiemaoshu
--%>
<form method="post" action="testModelAttribute">
<div>
用户id:<input type="text" name="uid" id="uid" value="1"/>
</div>
<div>
用户名称:<input type="text" name="uname" id="uname" value="xiemaoshu"/>
</div>
<div>
<input type="submit" value="提交"/>
</div>
</form>
</body>
- 进行修改操作的方法
@ModelAttribute//SpringMVC在执行映射请求方法之前,会先调用带有@ModelAttribute 注解的方法
public void getUser(@RequestParam(value = "uid",required = false) Integer uid,Map<String,Object> map){
//模拟从数据库中获取用户数据
User user =new User();
user.setUid(uid);
user.setUname("xiemaoshu");
user.setPassword("12345");
map.put("user",user);//将user数据保存到request请求域之中
System.out.println("获取uid = "+uid+" 的用户数据"+user);
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("执行修改操作:"+user);
return SUCCESS;
}
- 测试结果
- 后台输出
- 可以发现password不为null,这是因为在执行请求方法前,会先执行"@ModelAttribute"注解的方法
@ModelAttribute运行原理
-
运行流程:
- 执行@ModelAttribute注解修饰的方法:从数据库中取出数据,将数据放入到了Map中,键为:user
- SpringMVC从map中取出User对象,并把表单的请求参数付给该User对象的对应属性,
- SpringMVC把上述对象传入目标方法的参数.
-
注意:在ModelAttribute修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致
@ModelAttribute注解之源码分析
-
调用@ModelAttribute注解修饰的方法,实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中
-
解析请求处理器的目标参数,实际上该目标来自于WebDataBinder对象的target属性
-
创建WebDataBinder对象:
- 确定objectName属性:若传入的arrtName属性值为空字符串,则objctName为类名第一个字母小写.(=乳沟目标方法的POJO回信息使用了@ModelAttribute来修饰,则attrName值即为@ModelAttribute的value属性值==)
- 确定target属性:
- 在implicitModel中查找attriName对应的属性值.
- 若不存在:则验证当前的Hiddler是否使用了@SessionAttribute进行修饰,若使用了,则尝试从Session中获取arrtName所对应的属性值,若session中没有对应的属性值,则抛出异常.
- 若Handler没有使用@SessionAttribute进行修饰,或@SessionAttributes中没有使用value值指定的key和attrName相匹配,则通过反射创建了POJO对象.
-
SpringMVC把表单中请求参数赋给WebDataBinder的target属性.
-
SpringMBC会把WebDataBinder的attrName和target给到implicitModel
-
把webDataBinder的target作为参数传递给目标方法的入参.
- 在"@ModelAttribute"注解的方法中和请求的方法中打上断点