Spring MVC 提供了以下几种途径输出模型数据:
① ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
② Map 及 Model: 参数为 org.springframework.ui.Model、org.springframework.ui. ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中
③ @SessionAttributes: 将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
④ @ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中
下面来详细看看这四个部分的细节内容:
1)ModelAndView
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
• 添加模型数据:
① MoelAndView addObject(String attributeName, Object attributeValue)
②ModelAndView addAllObject(Map modelMap)
• 设置视图: ① void setView(View view) ② void setViewName(String viewName)
/**
* 目标方法的返回值可以是 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;
}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Success Page</title>
</head>
<body>
<h4>Success Page</h4>
time: ${requestScope.time }
</body>
</html>
2)Map 及 Model
Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
• 具体步骤:
① Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
② 如果方法的参数为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些参数。在方法体内,开发者可以通过这个参数对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。
/**
* 目标方法可以添加 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";
}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Success Page</title>
</head>
<body>
<h4>Success Page</h4>
names: ${requestScope.names }
</body>
</html>
3)@SessionAttributes注解
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC 将模型中对应的属性暂存到 HttpSession 中。@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型(Class类型)指定哪些模型属性需要放到会话中。
- @SessionAttributes(types=User.class) 会将隐含模型中所有类型 为 User.class 的属性添加到会话中。
- @SessionAttributes(value={“user1”, “user2”})
- @SessionAttributes(types={User.class, Dept.class})
- @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@SessionAttributes(value={"user"}, types={String.class})
@Controller
public class SpringMVCTest {
/**
* @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),
* 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)
* 注意: 该注解只能放在类的上面. 而不能修饰放方法.
*/
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Map<String, Object> map){
//这个user属性既被放到了request请求域中也放到了session请求域中
User user = new User("Tom", "123456", "tom@hlk.com", 15);
map.put("user", user);
map.put("school", "hlk");
return "success";
}
}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Success Page</title>
</head>
<body>
<h4>Success Page</h4>
request user: ${requestScope.user }
<br><br>
session user: ${sessionScope.user }
<br><br>
request school: ${requestScope.school }
<br><br>
session school: ${sessionScope.school }
</body>
</html>
4)@ModelAttribute注解
• 该标签主要用于参数的设置,通常在登录这些页面中需要进行传参,通过@ModelAttribute注释的方法会在控制器其他方法执行前先执行,所以可以在该方法中通过Model对象进行存储,之后在业务处理方法中直接引用即可,存储范围是在request中
• 在方法的参数前使用 @ModelAttribute 注解:
① 绑定请求参数到指定对象
只是此处多了一个注解@ModelAttribute("user"),它的作用是将该绑定的命令对象以“user”为名称添加到模型对象中供视图页面展示使用。我们此时可以在视图页面使用${user.username}来获取绑定的命令对象的属性。
public String testModelAttribute(@ModelAttribute("user") UserModel user)
② 在方法定义上使用 @ModelAttribute 注解
//@ModelAttribute注解注释void的方法时需要在方法中加入Model或Map对象进行传参
@ModelAttribute
public void userModer(@RequestParam("username") String username,@RequestParam("password") String password, Model model){
User user=new User();
user.setUsername(username);
user.setPassword(password);
model.addAttribute("user",user);
}
@RequestMapping(value="/register")
public String register(Model model){
User user=(User) model.asMap().get("user");
System.out.println("username:"+user.getUsername());
System.out.println("password:"+user.getPassword());
return "login";
}
在上述方法中@RequestParam注释主要是用于获取用户传递的参数,其中参数名称与用户提交的表单一致。
SpringMVC确定目标handler方法 POJO 类型参数传参的过程(重点理解):
1. 确定一个key:
① 若目标方法的POJO类型的参数没有使用@ModelAttribute注解作为修饰,则key为POJO类名第一个字母的小写
② 若使用了@ModelAttribute来修饰,则key为@ModelAttribute注解的value属性值
2. 在implicitModel中查找key对应的对象,若存在,则作为参数传入
① 若在@ModelAttribute标记的方法中在Map或model中保存过,且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域中