我们之前用 Servlet + JSP 开发 web 应用的时候,通常使用 Servlet 的四大作用域 request,session,page,application 给页面传值。Spring MVC 当然也支持这些 Servlet 的原生 API,但是,它也为我们提供了更加强大的 API 支持,下面我们我们来探讨一下 Spring MVC 是如何将数据传给页面的。
一、Map
第一种是 Map,没错,是 JDK 中的 Map 接口,我们只需要像操作 HashMap 键值对那样将要传递的数据以键值对的方式 put 到 Map 中即可,Spring MVC 会将它放入请求域中传递给页面。
@Controller
public class OutputController {
@GetMapping("/handle1")
public String handle(Map<String, Object> map) {
map.put("msg", "Hello Map!");
return "success";
}
}
在浏览器中输入 localhost:8080/handle1
二、Model
Model 是模型的意思,顾名思义,就是用来传递数据的,我们只需要调用 Model 对象的 addAttribute() 方法,将要传递的信息以键值对的方式添加进模型中,就可以将数据传递到页面了。
@Controller
public class OutputController {
@GetMapping("/handle2")
public String handle(Model model) {
model.addAttribute("msg", "Hello Model!");
return "success";
}
}
在浏览器中输入 localhost:8080/handle2
三、ModelMap
ModelMap 是 Map 的实现类,但它叫 ModelMap,说明融合了 Model 的特性,所以使用方式上和 Model 类似。
@Controller
public class OutputController {
@GetMapping("/handle3")
public String handle(ModelMap mp) {
mp.addAttribute("msg", "Hello ModelMap!");
return "success";
}
}
在浏览器中输入 localhost:8080/handle3
四、ModelAndView
以前前后端不分的情况下,ModelAndView 应该是最最常见的返回值类型了,现在前后端分离后,后端都是以返回 JSON 数据为主了。后端返回 ModelAndView 这个比较容易理解,开发者可以在 ModelAndView 对象中指定视图名称,也可以绑定数据。
@Controller
public class OutputController {
@GetMapping("/handle4")
public ModelAndView handle() {
ModelAndView mv = new ModelAndView("success");
mv.addObject("msg", "Hello ModelAndView!");
return mv;
}
}
在浏览器中输入 localhost:8080/handle4
扩展:Map、Model、ModelMap 的关系
我们在每一个 handle() 方法里加一句 System.out.println("xxx 的类型:" + xxx.getClass());
在控制台打印它们的类型。
结果总是惊人的相似
它们的类型都是
org.springframework.validation.support.BindingAwareModelMap
我们找到这个类
public class BindingAwareModelMap extends ExtendedModelMap {
@Override
public Object put(String key, Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
}
发现它继承自 ExtendedModelMap
public class ExtendedModelMap extends ModelMap implements Model {
@Override
public ExtendedModelMap addAttribute(String attributeName, @Nullable Object attributeValue) {
super.addAttribute(attributeName, attributeValue);
return this;
}
}
答案已经很明了了,这个类实现了即继承了 ModelMap 类,又实现了 Model 接口,还没完,还剩下 ModelMap
public class ModelMap extends LinkedHashMap<String, Object> {
/**
* Construct a new, empty {@code ModelMap}.
*/
public ModelMap() {
}
}
ModelMap 继承自 LinkedHashMap,而 LinkedHashMap 就不用我多说了,它是 Map 的实现类。
下面用一张图来清楚的表示它们之间的关系。