四、SpringMVC使用域对象共享数据
在SpringMVC中常用的域有以下三个: 1、request:数据在当前请求有效,请求转发后有效,重定向无效 2、session:数据在关闭浏览器前有效,中途关闭服务器,数据钝化(还在),重启浏览器数据又会活化(还能用) 3、application:数据在关闭服务器前有效(关闭浏览器数据还在)
有些人可能会问了,之前javaweb中,不是还有一个叫pageContext的域对象吗,解释一下,因为这个pageContext是用在jsp文件中的,但是jsp这种文件现在好像过时了,所以呢,就不用这个了。
那么,我们的SpringMVC这个框架怎么使用域对象呢?请看:
4.1 使用ServletAPI向request域对象共享数据
先写一个DomainController.java文件
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class DomainController {
@RequestMapping("/testRequestByServletAPI")
public String testRequestByServletAPI(HttpServletRequest request){
request.setAttribute("testRequestScope","Hello ServletAPI");
return "success";
}
}
然后写一个成功后跳转的页面,用来显示request域对象中的数据: success.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>成功页面</title>
</head>
<body>
<h1>跳转成功</h1>
<p th:text="${testRequestScope}"/>
</body>
</html>
最后写一个首页,用来编写各个超链接跳转到各个servlet路径下。 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a th:href="@{/testRequestByServletAPI}">通过ServletAPI向request域对象共享数据</a>
</body>
</html>
启动服务器后,点击超链接 显示如下:
4.2 使用ModelAndView向request域对象共享数据(官方推荐使用这个)
ModelAndView有Model和View的功能,Model主要用于向请求域共享数据,View主要用于设置视图,实现页面跳转。
直接贴代码: 向Controller.java中添加方法:
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView mav = new ModelAndView();
mav.addObject("testRequestScope","Hello ModelAndView");
mav.setViewName("success");
return mav;
}
向index页面添加超链接跳转:
<a th:href="@{/testModelAndView}">通过ModelAndView向request域对象共享数据</a><br>
重启服务器: 点击后 request中的数据成功显示:
4.3 使用Model向request域对象共享数据
上面的方法好像有点小麻烦,代码也好多哦,咱脑子笨,习惯了那种return后边加网页名的写法了。突然要写这种,感觉还不如写ServletAPI那种呢对吧。但是,其实有更好的写法,代码又少,写起来又顺手。那就是使用我们的Model 请看代码:
首先在Controller下添加方法:
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope", "Hello Model");
return "success";
}
然后写一个页面跳转的代码:
<a th:href="@{/testModel}">通过Model向request域对象共享数据</a><br>
重启服务器,让我们来看看: 成功上岸!!!
4.4 使用Map向request域对象共享数据
直接写代码吧: 先向Controller中添加方法:
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testRequestScope","Hello Map");
return "success";
}
然后在index中写一个超链接:
<a th:href="@{/testMap}">通过Map向request域对象共享数据</a><br>
重启服务器: 点击最新添加的超链接: 成功!!!!
4.5 使用ModelMap向request域对象共享数据
还有一种ModelMap的使用方式,代码也很简单,类似于前面的Model。所以直接贴代码吧: Controller下添加方法:
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope", "Hello ModelMap");
return "success";
}
首页添加超链接:
<a th:href="@{/testModelMap}">通过ModelMap向request域对象共享数据</a><br>
重启服务器: 选择最新添加的超链接,显示如下: nice!
4.6 Model、ModelMap、Map的关系
这个Model、ModelMap和Map用起来感觉好像差不多呀,用着都很舒服,那他们之间有没有什么内在的联系嘞?答案是肯定的,下边,我们就来扒他的源码看看吧,嘿嘿嘿。
首先,我们把这三个东西打印出来看一下,修改之前的源码如下:
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope", "Hello Model");
System.out.println("Model:"+model);
return "success";
}
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testRequestScope","Hello Map");
System.out.println("Map:"+map);
return "success";
}
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope", "Hello ModelMap");
System.out.println("ModelMap:"+modelMap);
return "success";
}
重启服务器后,分别点击这三个超链接: 看一下控制台输出的内容: 可见,格式那是一毛一样!!!有没有这么巧!!!难道,其实他们是同一个类????来来来,让我们分别输出他们的类名,嘿嘿嘿。
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope", "Hello Model");
System.out.println("Model:"+model.getClass().getName());
return "success";
}
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testRequestScope","Hello Map");
System.out.println("Map:"+map.getClass().getName());
return "success";
}
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope", "Hello ModelMap");
System.out.println("ModelMap:"+modelMap.getClass().getName());
return "success";
}
然后重启服务器,再次点击下面的三个超链接,此时我们的控制台显示如下: 恐怖吧!!!!他们居然!!!背地里偷偷都用了BindingAwareModelMap这个类。(提示一下,Model和Map这两个是接口哦,所以输出的是他们的实现类,至于ModelMap吧,他是一个类,但是这个类呢他继承了LinkedHashMap,而这个LinkedHashMap又实现了Map接口,因此,ModelMap也间接实现了Map接口,也就是说,ModelMap是Map的实现类) 然后然后,我们通过IDEA,单击ModelMap类并按Ctrl+H,打开ModelMap的“族谱”: 这里,我们从他们的族谱可以看到我们刚才提到的输出的类BindingAwareModelMap: 我们进去看看: 发现,妈耶,他继承了ExtendedModelMap这个类,行吧,我们再顺藤摸瓜过去 我们再打开ExtendedModelMap类,可以看到他不但继承了ModelMap还实现了Model接口。 如此,关系就很清楚了。简单来说,我们刚才用的Model、Map还有ModelMap的关系就是: ModelMap的爸爸LinkedHashMap实现了Map这个接口 然后呢,根据多态的原则,祖先可以“装孙子”(我个人的记法和叫法哈),因此 这里BindingAwareModelMap的爸爸ExtendedModelMap他又是ModelMap的儿子,又实现了Model接口。(他爸爸事情真多) 所以呢,这个BindingAwareModelMap就 1、间接实现了Model,也就是Model的实现类 2、作为ModelMap的孙子,他允许让ModelMap“装孙子” 3、ModelMap的爸爸LinkedHashMap实现了Map,因此,BindingAwareModelMap又间接间接地实现了这个Map,也就是Map的实现类。
知识点: 其实,无论是用ServletAPI、Model、Map还是ModelMap的方式,他最终底层都要经过ModelAndView(这也是官方推荐的原因)也许这样会比较快吧,毕竟少了中间商(说文艺一点,虽然说条条大路通罗马,但是两点之间,线段最短),但是代码写起来是会有一丢丢的不适应哈(当然,也可能是我自己个人感觉)。
不相信上面这个知识点的可以自己去一点点调试哦。或者看看别人调试,这里给个视频链接。
4.7 使用ServletAPI向session域对象和application域对象共享数据
为什么要讲ServletAPI不讲其他的嘞,首先吧,用得少,其次,前辈也建议使用这种,所以就讲这种啦!!!
直接贴代码吧: 先写两个控制器方法:
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope","Hello Session");
return "success";
}
@RequestMapping("testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope","Hello Application");
return "success";
}
再在index中写两个超链接
<a th:href="@{/testSession}">通过ServletAPI向session域对象共享数据</a><br>
<a th:href="@{/testApplication}">通过ServletAPI向application域对象共享数据</a><br>
然后我们在success页面中添加以下代码,让他显示:
<p th:text="${session.testSessionScope}"/>
<p th:text="${application.testApplicationScope}"/>
重启服务器: 点击刚才添加的两个超链接,分别显示如下:
|