springMvc 处理模型数据 ModelAndView Map及Model @SeesionAttributes @ModelAttribute
1、Spring MVC 提供了以下几种途径输出数据到模型中:(1)ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据(2)Map 及 Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中
目录
1、Spring MVC 提供了以下几种途径输出数据到模型中:
1、Spring MVC 提供了以下几种途径输出数据到模型中:
(1)ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据
(2)Map 及 Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
(3)@SessionAttributes: 将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性
(4)@ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中
2、ModelAndView类
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
(1)添加模型数据方法
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap– )
(2)设置视图方法:
void setView(View view)
void setViewName(String viewName)
(3)演示
前端
<body>
<a href="springmvc/testModelAndView">Test ModelAndView</a>
</body>
服务端代码
package com.atguigu.springmvc.handlers
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest{
private static final String SUCCESS="success";
@RequestMapping(value="/testModelAndView")
public String ModelAndView testModelAndView(){
String viewName=SUCCESS;
ModelAndView modelAndView=new ModelAndView(viewName);
//添加模型数据到ModelAndView中
modelAndView.addObject("time",new Date());
return modelAndView;
}
}
说明:SpringMVC会把ModelAndView的model中的数据放入到request域对象中
进入success.jsp(转到的页面也是MVC模型的V)。域对象就可以调用啦
<body>
<h4>Success Page</h4>
time:${requestScope.time}
</body>
3、Map及Model
SpringMVC在内部使用了一个org.springframework.ui.Model 接口存储模型数据。该方法主要用于添加Map类型数据进入模型,实际上也可以添加Model类型或ModeIMao类型参数。实际上形参是一个ExtendedModeMap实例对象,由图可见,该对象实现了Map接口,和Model接口,因此可以添加他们的类型参数,但是一般用于添加Map类型参数到请求域request对象中
Model接口
作用:将值存放到request对象

具体步骤:
(1)SpringMVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
(2)如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
package com.atguigu.springmvc.handlers
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest{
private static final String SUCCESS="success";
@RequestMapping(value="/testMap")
public String testMap(Map<String,Object> map){
map.put("names",Arrays.asList("Tom","Jerry","Mike"));
return SUCCESS;
}
}
前端
<body>
<a href="springmvc/testMap">Test Map</a>
</body>
视图Jsp
<body>
<h4>Success Page</h4>
time:${requestScope.time}
names:${requestScope.names}
</body>
4、@SessionAttributes注解
@SessionAttributes注解的作用是向服务器session添加键值对
该注解只能放在类的上面,不能放在方法上面。
如果不加@SessionAttributes注解,就会像前面一样加到请求域里面,加了@SessionAttributes注解才会变成session,就会同时放在请求域和session
用法:
@SessionAttributes(types=User.class) 会将隐含模型中所有类型为 User.class 的属性添加到会话(session)中。
@SessionAttributes(value={“user1”, “user2”}) 会将键为user1,和user2 的属性值添加到会话中
@SessionAttributes(types={User.class, Dept.class}) 会将User对象和 Dept对象 添加的会话中
@SessionAttributes(value={“user1”, “user2”}, types={Dept.class}) 会将键为user1 和 user2 以及 Dept类对象添加到会话中
演示:
package com.atguigu.springmvc.handlers
//除了键位user的属性值,所有String类型的属性值都会进入session
@SessionAttributes(value={"user"},types={String.class})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest{
private static final String SUCCESS="success";
@RequestMapping(value="/testSessionAttributes")
public String testSessionAttributes(Map<String,Object> map){
User user=new User("Tom","123456","tom@atguigu.com",15);//上面那个文章的user
map.put("user",user);
return SUCCESS;
}
}
前端
<body>
<a href="springmvc/testSessionAttributes">Test SessionAttributes</a>
</body>
Jsp页面
<body>
<h4>Success Page</h4>
time:${requestScope.time}
names:${requestScope.names}
session user:${sessionScope.user}
</body>
注意:关于异常
如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用请求消息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常
5、@ModelAttribute注解
5.1 @ModelAttribute注解详细介绍
引入问题:一条数据记录,三个字段要修改两个字段,有一个字段不能修改。
问题:如果按照常规操作,new一个新的对象作为数据记录,修改两个属性,另一个不变。但是这样的效果就是,修改了两个,不能修改的变成空了。

解决思路。从数据库获取该条记录的对象(是从数据库获取的,不是new的),这样这三个属性值都是数据库本身的值了。然后再修改,就可以达到效果啦

有@ModelAttribute标记的方法,会在每个目标方法执行之前被SpringMVC调用(先调用@ModelAttribute标记的方法,再调用目标方法)
代码演示
要求:模拟修改操作
1.原始数据为: 1, Tom, 123456,tom@atguigu.com,12 (实际不是数据库读取的,是自己手动添加的原始数据)
2.密码不能被修改.
3,表单回显,模拟操作直接在表单填写对应的属性值
创建User类,这个POJO对象可以自动获取完表单内容
package com.atguigu.springmvc.entities;
public class User{
private Integer id;
private String username;
private String password;
private String email;
private int age;
//空参构造器,有参构造器,get方法,set方法,toString方法
}
前端首页 index.jsp
<body>
<form action="springmvc/testModelAttribute" method="post">
<!--一般id值都是隐藏的-->
<input type="hidden" name="id" value="1">
username<input type="text" name="username" value="Tom">
email:<input type="text" name="email" value="tom@atguigu.com">
age:<input type="text" name="age" value="12">
<input type="submit" value="Submit">
</form>
</body>
服务端
package com.atguigu.springmvc.handlers
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest{
private static final String SUCCESS="success";
@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@atguigu.com",12);
System.out.println("从数据库中获取一个对象:"+user);
map.put("user",user);
}
}
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("修改"+user);
return SUCCESS;
}
}
运行流程说明:
① 执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放入到了Map中.键为: user
② SpringMVC从Map中取出User对象,并把表单的请求参数赋给该User对象的对应属性.
③ SpringMVC把上述对象传入目标方法的参数.
注意:在@ModelAttribute修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致!
5.2 源码分析流程
step1 调用@ModelAttribute注解修饰的方法,实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中.
step2 解析请求处理器的目标参数,实际上该目标参数来自于@WebDateBinder对象的target属性
(1)创建WebDataBinder对象
I 确定objectName属性:若传入的attrName属性值为"",则objectName为类名第一个字母小写。
注意:attrName. 若目标方法的POJO属性使用了@ModelAttribute来修饰,则attrName值即为@ModelAttribute的value属性值
II 确定target属性:
① 在implicitModel中查找attrName对应的属性值.若存在, ok
② 若不存在:则验证当前Handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值.若session中没有对应的属性值,则抛出了异常.
③ 若Handler没有使用@SessionAttributes进行修饰,或@SessionAttributes中没有使用value值指定的key和attrName相匹配,则通过反射创建了POJO对象
(2) SpringMVC把表单的请求参数赋给了WebDataBinder的target对应的属性。
(3) *SpringMVC会把WebDataBinder的attrName和target给到implicitModel,进而传到request域对象中
(4)把WebDataBinder的target作为参数传递给目标方法的入参.
进一步简化整理以上过程:
SpringMVC确定目标方法POJO类型入参的过程:
(1)确定一个key:
1),若目标方法的POJ0类型的参数没有使用@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中
5.3 @ModelAttribute注解修饰入参
上一节已经讲过了全套,这里专门讲下修饰入参
总之常用的是,入参用了@ModelAttribute注解修饰,就可以自己取键的名字了,如果没用该注解修饰,默认键名为POJO类名第一个字母的小写。入参不用POJO类名第一个字母的小写命名,同时又没用@ModelAttribute注解修饰,并自己取名,springmvc就找不到。
(1)有@ModelAttribute标记的方法,会在每个目标方法执行之前被SpringMVC调用!
(2)@ModelAttribute注解也可以来修饰目标方法POJO类型的入参,其value属性值有如下的作用:
1). SpringMvC会使用value属性值在implicitModel中查找对应的对象,若存在则会直接传入到目标方法的入参中.
2). SpringMvC会使用value为key, POJO类型的对象为value,存入到request中.
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)