目录
2、使用 ServletAPI 向 request 域对象共享数据(不建议使用)
3、使用ModelAndView向request域对象共享数据(建议使用)
8、控制器方法执行后都会返回统一的 ModelAndView 对象
10、向application域(ServletContext域)共享数据
0、准备工作:创建模块并配置
① 创建目录如下:
② TestController 类的内容如下:
@Controller
public class TestController {
@RequestMapping("/")
public String index(){
return "index";
}
}
③ springMVC.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cntext="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置扫描组件 -->
<cntext:component-scan base-package="com.zyj.mvc.controller"></cntext:component-scan>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
④ index.html 内容如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>
⑤ web.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置SpringMVC的前端控制器DispatcherServlet -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
1、回顾域对象
四大域对象:
1、pageContext (PageContextImpl 类) :当前 jsp 页面范围内有效,由于 jsp 已经过时,在 SpringMVC 中不加以使用
2、request (HttpServletRequest 类) :一次请求内有效
3、session (HttpSession 类):一个会话范围内有效(打开浏览器访问服务器,直到关闭浏览器)
钝化:当服务器正常关闭时,还存活着的session(在设置时间内没有销毁) 会随着服务器的关闭被以文件(“SESSIONS.ser”)的形式存储在tomcat 的work 目录下,这个过程叫做Session 的钝化。
活化:当服务器再次正常开启时,服务器会找到之前的“SESSIONS.ser” 文件,从中恢复之前保存起来的Session 对象,这个过程叫做Session的活化。
注:钝化与活化实际上就是session的序列化与反序列化。详细可以参考博客:Session 的钝化与活化_点滴记录-CSDN博客_session钝化和活化
4、application (ServletContext 类) :整个 web 工程(应用)范围内都有效(只要 web 工程不停止,数据都在),在服务器启动时创建,关闭时销毁。由于范围太大也少用。
域对象是可以像 Map 一样存取数据的对象。四个域对象功能一样。不同的是它们对数据的存取范围。
虽然四个域对象都可以存取数据。在使用上它们是有优先顺序的。
四个域在使用的时候,优先顺序是,他们从小到大的范围的顺序。:
pageContext ====>>> request ====>>> session ====>>> application
2、使用 ServletAPI 向 request 域对象共享数据(不建议使用)
① 创建 ScopeController 控制器类,内容如下:
@Controller
public class ScopeController {
// 测试使用ServletAPI向request域对象共享数据
@RequestMapping("/testRequestByServletAPI")
public String testRequestByServletAPI(HttpServletRequest request){
request.setAttribute("testRequestScope", "hello,ServletAPI");
return "success";
}
}
② 创建 success.html 页面,用来测试跳转是否成功
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>success</title>
</head>
<body>
这是success.html页面<br>
<p th:text="${testRequestScope}"></p>
</body>
</html>
注:p 标签报错是正常现象,如果不让它报错,可以在 设置-编辑器-检查 中进行设置,如下图:取消打勾即可
③ 最后在首页 index.html 中添加测试的跳转链接
<!-- 测试使用ServletAPI向request域对象共享数据 -->
<a th:href="@{/testRequestByServletAPI}">测试使用ServletAPI向request域对象共享数据</a>
④ 结果如下图,传输成
3、使用ModelAndView向request域对象共享数据(建议使用)
① 在 ScopeController 类中添加方法
// 测试使用ModelAndView向request域对象共享数据
// 注意使用该方法必须返回 ModelAndView 对象
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView mav = new ModelAndView();
// 处理模型数据:即向请求域request共享数据
mav.addObject("testRequestScope", "hello,ModelAndView");
// 设置视图名称
mav.setViewName("success");
return mav;
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试使用ModelAndView向request域对象共享数据 -->
<a th:href="@{/testModelAndView}">测试使用ModelAndView向request域对象共享数据</a><br>
③ success.html 页面不变,运行测试,结果如下,传输成功
4、使用Model向request域对象共享数据
① 在 ScopeController 类中添加方法
// 测试使用Model向request域对象共享数据
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope", "hello,model");
return "success";
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试使用Model向request域对象共享数据 -->
<a th:href="@{/testModel}">测试使用Model向request域对象共享数据</a><br>
③ success.html 页面不变,运行测试,结果如下,传输成功
5、使用map向request域对象共享数据
在方法的形参中添加 Map 类型的数据,向 map 中存储的数据就是向 request 域中共享的数据
① 在 ScopeController 类中添加方法
// 测试使用map向request域对象共享数据
@RequestMapping("testMap")
public String testMap(Map<String, Object> map){
map.put("testRequestScope", "hello,map");
return "success";
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试使用map向request域对象共享数据 -->
<a th:href="@{/testMap}">测试使用map向request域对象共享数据</a><br>
③ success.html 页面不变,运行测试,结果如下,传输成功
6、使用ModelMap向request域对象共享数据
① 在 ScopeController 类中添加方法
// 测试使用ModelMap向request域对象共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope", "hello,ModelMap");
return "success";
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试使用ModelMap向request域对象共享数据 -->
<a th:href="@{/testModelMap}">测试使用ModelMap向request域对象共享数据</a><br>
③ success.html 页面不变,运行测试,结果如下,传输成功
7、Model、ModelMap、Map的关系
在上方使用这三种共享数据的方法中输出对应的形参,结果如下(注释为输出的结果)
System.out.println(model); //{testRequestScope=hello,model}
System.out.println(map); //{testRequestScope=hello,map}
System.out.println(modelMap); //{testRequestScope=hello,ModelMap}
可以发现输出的格式一样,再输出对应形参的全类名(实现类),结果如下:
System.out.println(model.getClass().getName()); //org.springframework.validation.support.BindingAwareModelMap
System.out.println(map.getClass().getName()); //org.springframework.validation.support.BindingAwareModelMap
System.out.println(modelMap.getClass().getName()); //org.springframework.validation.support.BindingAwareModelMap
可以发现这三个的实现类都一样
查看 ModelMap类 的层次结构
// 查看 BindingAwareModelMap 类的源码,发现如下
public class BindingAwareModelMap extends ExtendedModelMap {}
// 查看 ExtendedModelMap 类的源码,发现如下,所以 BindingAwareModelMap 可以实例化 ModelMap 和 Model
public class ExtendedModelMap extends ModelMap implements Model {}
// 查看 ModelMap 的源码,发现如下,而 LinkedHashMap 又实现了 Map 接口,所以 BindingAwareModelMap 可以实例化 Map
public class ModelMap extends LinkedHashMap<String, Object> {}
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {}
总结:
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
8、控制器方法执行后都会返回统一的 ModelAndView 对象
// 测试使用ServletAPI向request域对象共享数据
@RequestMapping("/testRequestByServletAPI")
public String testRequestByServletAPI(HttpServletRequest request){
request.setAttribute("testRequestScope", "hello,ServletAPI");
return "success";
}
在上述方法的任一行打上断点,根据前面所学,我们知道请求分发和处理都是通过 DispatcherServlet 进行的,在调试器中找到与 DispatcherServlet 有关的方法并点击,发现跳转到 mv 属性上,而 mv 是 ModelAndView 对象,所以最后会返回 ModelAndView 对象
其他控制器方法也是一样,在方法任一行打上断点进行调试,都可以在调试器的方法堆中找到上述方法,且都是 mv 这一行,所以控制器方法执行后都会返回统一的 ModelAndView 对象
9、向session域共享数据
这里通过 ServletAPI 向session域共享数据
① 在 ScopeController 类中添加方法
// 测试向session域共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "hello,session");
return "success";
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试向session域共享数据 -->
<a th:href="@{/testSession}">测试向session域共享数据</a><br>
③ 在 success.html 页面添加显示 Session 域的内容
<p th:text="${session.testSessionScope}"></p>
④ 运行测试,结果如下,传输成功
10、向application域(ServletContext域)共享数据
① 在 ScopeController 类中添加方法
// 测试向application域(ServletContext域)共享数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "success";
}
② 在首页 index.html 中添加测试的跳转链接
<!-- 测试向application域(ServletContext域)共享数据 -->
<a th:href="@{/testApplication}">测试向application域(ServletContext域)共享数据</a><br>
③ 在 success.html 页面添加显示 Session 域的内容
<p th:text="${application.testApplicationScope}"></p>
④ 运行测试,结果如下,传输成功