Spring MVC 通过 @RequestMapping 将请求引导到处理方法上,使用合适的方法签名将请求消息绑定到入参中。方法入参绑定请求消息只是处理方法的第一步,还有更重要的任务等待完成,即根据入参执行相应的逻辑,产生模型数据,导向到特定视图中。
如何将模型数据暴露给视图是 SpringMVC 框架的一项重要工作,SpringMVC 提供了多种途径输出模型数据:
1. @ModelAndView:处理方法返回值类型为 ModelAndView时,方法体即可通过该对象添加模型数据。
2. @ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
3. @Map 及 Model:入参为 org.springframework.ui.Model、org.soringframework.ui.ModelMap 或 java.util.Map 时,处理方法返回时,Map中的数据会自动添加到模型中。
4. @SessonAttribute:将模型中的某个属性暂时存到 HttpSession 中,以便多个请求之间可以共享这个属性。
一、ModelAndView
控制器处理方法的返回值如果为 ModelAndView,则其既包含视图信息,也包含模型数据信息,这样 SpringMVC 就可以使用视图对模型数据进行渲染了。可以简单地将模型数据看成一个 Map<String, Object>对象。
在处理方法的方法体中,可以使用如下方法添加模型对象:
1. ModelAndView addObject(String attributeName, Object attributeValue)
2. ModelAndView addAllObject(Map<String, ?> modelMap)
可以通过如下方法设置视图
1. void setView(View view):指定一个具体的视图对象
2. void setViewName(String viewName):指定一个逻辑视图名
测试:
@RequestMapping("/springmvc")
@Controller
public class SpringTest
{
//SpringMVC 会把 ModelAndView 的模型数据放到请求域中去
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView()
{
String viewName = "success";
//指定跳转的逻辑视图名为 success
ModelAndView modelAndView = new ModelAndView(viewName);
//添加模型数据到ModelAndView
modelAndView.addObject("time", new Date());
return modelAndView;
}
}
<body>
<a href="springmvc/testModelAndView">Test ModelAndView</a>
</body>
<body>
<h4>Success Page</h4>
time: ${requestScope.time }
</body>
二、Map 及 Model
SpringMVC 在内部使用一个 org.springframework.ui.Model 接口存储模型数据,它的功能类似于 java.util.Map,但它比Map易用。org.springframework.ui.ModelMap实现了 Map 接口,而 org.springframework.ui.ExtendedModelMap 继承于 ModelMap 同时实现了 Model 接口。
SpringMVC 在调用方法前会创建一个隐含的模型对象,作为模型数据的存储容器,我们称之为 “隐含模型”。如果处理方法的入参为 Map 或 Model 类型,SpringMVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型数据中添加新的属性数据。
测试:
//目标方法可以添加 Map 类型的参数,也可以是 Model 类型或者 ModelMap 类型的参数
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map)
{
map.put("names", Arrays.asList("tom", "jack", "mike"));
return "success";
}
<a href="springmvc/testMap">Test Map</a>
map: ${requestScope.names }
SpringMVC 一旦发现处理方法有 Map 或 Model 类型的入参,就会请求内在的隐含模型对象传递给这些参数,因此在方法体中可以通过这个入参对模型对象的数据进行读写操作。
二,@ModelAttribute
在方法定义上使用 @ModelAttribute 注解:SpringMVC 在调用目标处理方法前,会逐个调用在方法上标注了 @ModelAttribute 的方法
在方法的入参前使用 @ModelAttribute 注解:
1. 可以从隐含对象中获取隐含的模型数据对象,再将请求参数绑定到对象中,再传入入参
2. 将方法入参对象添加到模型中
如果希望将方法入参对象添加到模型中,仅需在相应的入参前使用@ModelAttribute注解即可,
public String list(@ModelAttribute("teachet") Teacher teachet){
Teacher teacher = new Teacher();
teacher.setAge(24);
teacher.setId(1);
teacher.setName("json");
return "teacher/list";
}
SpringMVC将请求消息绑定到Teacher对象中,然后再以“teacher”为键将Teacher对象放到隐藏模型中,最后在视图对象list.jsp中就可以使用${teacher.name}取值显示了。
@ModelAttribute也可以在方法上使用,SpringMVC在调用目标方法前,会先逐个调用在方法级上标注了@ModelAttribute的方法,并将这些方法的返回值添加到隐藏模型中。
注意:在②处,当获得整合版本的user对象后,会将其添加到模型中。
四,@SessionAttributes
如果希望在多个请求之间共用某个模型属性数据,则可以在控制器类标注个 @SessionAttributes,SpringMVC 会将模型中对应的属性暂存到 HTTPSession 中。
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
1. @SessionAttributes(types=User.class)会将隐含模型中所有类型为 User 的属性添加到会话中
2. @SessionAttributes(value={"user1", "user2"})将名为 user1 和 user2 的模型属性添加到会话中
3. @SessionAttributes(types={"User.class", "Dept.class"})将模型中所有类型为 User 及 Dept 的属性添加到会话中
4. @SessionAtributes(value={"user1", "user2"}, types={Dept.class})将名为 user1 和 user2 的模型属性添加到会话中,同时将所有类型为 Dept 的模型属性添加到会话中
@SessionAttributes(value={"user"}, types={String.class})
@RequestMapping("/springmvc")
@Controller
public class SpringTest
{
private static final String SUCCESS = "success";
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Map<String, Object> map)
{
User user = new User("Jack", "123");
map.put("user", user);
map.put("msg", "hello");
return SUCCESS;
}
}
<a href="springmvc/testSessionAttributes">Test SessionAttributes</a>
request user: ${requestScope.user }
<br><br>
request msg: ${requestScope.msg }
<br><br>
session user: ${sessionScope.user }
<br><br>
session msg: ${sessionScope.msg }
由结果可以看出,被 @SessionAttributes 注解修饰后,模型属性不仅存在于请求域还存在于会话域。需要注意的是@SessionAttributes 注解只能用于修饰类而不能用于方法上。
补充:
@RequestMapping(value="/helloworld")
public String helloWorld(User user)
{
return "helloworld";
}
框架提前帮你写了一句model.addAttribute("user",user)。
而且特别需要注意注意,无论model中是否有key为user的属性,都要求User类有无参构造方法