一、域对象共享数据
-
SpringMVC 中有哪些域对象?
- Request请求域,代表一次请求,从浏览器开启到关闭
- Session请求域,代表一次会话,从服务器开启到关闭【一次getSession获得了cookie,这个会话没关闭,之后获取的都是这个session】
- Application请求域,代表整个应用的范围,一个项目对应一个
- pageContext请求域,代表当前的jsp文件
-
如何选择域对象?
- 可以实现功能且范围最小的域对象
-
准备工作:构建我们的SpringMVC的框架
- 创建新的模块,确定打包方式和配置依赖
- 添加webapp模块,然后在项目结构中添加web.xml文件
- 到web.xml文件中注册过滤器和前端控制器
- 编写我们SpringMVC的核心配置文件
- 扫描组件
- 添加 thymeleaf 的视图解析器
- 创建我们的控制器【一个类文件】
- 创建我们的前端页面
-
我们将数据添加到请求域中了,那么我们如何获取数据呢?
- 首先我们要知道域中的数据是以键值对的形式存在的
- 在使用了thymeleaf的html页面中获取共享到request中的数据,我们可以直接通过键值对的key来获取数据
- 如果是获取session中的数据,采用session.共享数据的键
- 如果是获取application中的数据,采用application.共享数据的键
-
在我们原生的 Servlet 中为我们提供了三种操作域中数据的方法:
- setAttribute 方法,向域中添加数据
- getAttribute 方法,获取域中数据
- removeAttribute ,删除域中数据
-
接下来我们介绍几种向域中添加数据的方式:【如何演示具体操作】
- 第一步,编写我们在首页中写的超链接,作为请求
- 第二步,在控制器中编写我们的控制器方法,用作处理请求【向请求域对象中添加数据】
- 第三步,我们在最后跳转的页面中去获取一下我们添加的数据,验证是否添加成功
-
因为我们获取域对象的数据根据域的不同在此处分为三种,我在这里直接给出跳转页面的代码
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>用作请求匹配成功后的跳转页面</title> </head> <body> <h1>跳转页面成功</h1> <!--我们在前面将数据添加到了共享域中之后,我们可以在显示页面获取这些共享数据--> <!--因为我们要获取的是在request中的数据,所以我们直接通过key获取即可,尽管IDEA中会显示报错,但是实际没有问题--> <p th:text="${testRequestScope}"></p> <p th:text="${session.testSessionScope}"></p> <p th:text="${application.testApplicationScope}"></p> </body> </html>
$ 向Request域对象共享数据
$$ ServletAPI
编写我们的请求
<a th:href="@{/testRequestByServletAPI}">通过原生ServletAPI向Request请求域添加数据</a><br>
编写我们的控制器方法
// 通过原生的Servlet的API向域中共享数据
@RequestMapping("/testRequestByServletAPI")
public String testRequestByServletAPI(HttpServletRequest request){
request.setAttribute("testRequestScope", "Hello, Request");
return "success";
}
$$ ModelAndView
- 模型就是我们要往域中共享数据的对象,视图是我们要往视图解析器里面传递的内容
- 对于其他几种方式,通过前端控制器处理之后,最后都是包装成了ModelAndView对象
编写我们的请求
<a th:href="@{/testModelAndView}">通过ModelAndView向Request请求域添加数据</a><br>
编写我们的控制器方法
// 通过ModelAndView向域中共享数据
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/*
我们的ModelAndView包含两个方面:
(1)M 代表模型,用来向请求域共享数据
(2)V 代表视图,用于页面跳转
*/
// 创建我们ModelAndView的对象
ModelAndView mav = new ModelAndView();
// 然后为其添加数据,就是向我们的 request请求域添加数据
mav.addObject("testRequestScope", "Hello, ModelAndView");
// 然后通过这个对象指定视图名称
mav.setViewName("success");
return mav;
}
$$ Model
编写我们的请求
<a th:href="@{/testModel}">通过Model向Request请求域添加数据</a><br>
编写我们的控制器方法
// 通过Model向域中共享数据
@RequestMapping("/testModel")
public String testModel(Model model){
// 添加数据
model.addAttribute("testRequestScope", "Hello, Model");
return "success";
}
$$ Map集合
编写我们的请求
<a th:href="@{/testMap}">通过Map向Request请求域添加数据</a><br>
编写我们的控制器方法
// 通过Map向域中共享数据
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
// 通过map的put方法添加键值对
map.put("testRequestScope", "Hello, Map");
return "success";
}
$$ ModelMap
编写我们的请求
<a th:href="@{/testSession}">通过ServletAPI向Session请求域对象中添加数据</a><br>
编写我们的控制器方法
// 通过ModelMap向域中共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
// 通过map的put方法添加键值对
modelMap.addAttribute("testRequestScope", "Hello, ModelMap");
return "success";
}
- 我们的Model、Map、ModelMap之前是存在联系的,两个接口一个类
- 他们最终都是由同一个类实现的 ,BindingAwareModelMap 类
$ 通过ServletAPI向Session域对象共享数据
编写我们的请求
<a th:href="@{/testSession}">通过ServletAPI向Session请求域对象中添加数据</a><br>
编写我们的控制器方法
// 通过ServletAPI向我们的Session请求域中添加共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "Hello, Session");
return "success";
}
$ 通过ServletAPI向Application域对象共享数据
<a th:href="@{/testApplication}">通过ServletAPI向Application请求域对象中添加数据</a>
// 向我们Application请求域中添加数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
// 通过session的getServletContext方法获取我们的application对象
ServletContext application = session.getServletContext();
// 然后调用我们的add~方法向域中添加数据
application.setAttribute("testApplicationScope", "Hello, Application");
// 返回页面
return "success";
}
二、视图
-
什么是视图?
- 在SpringMVC中,视图是 View 接口
- 将模型中的数据经过渲染后展示给用户
-
视图分为哪些种类?【列举几种常见的】
- 转发视图
- 重定向视图
- 引入 jst 的依赖后,转发视图会自动转化为 jstView
- 如是通过Thymeleaf解析之后得到的就是 ThymeleafView
-
接下来我们将展开介绍几种常见的视图
$ ThymeleafView
- 我们导入了Thymeleaf的框架的依赖,并且在SpringMVC的核心配置文件中使用了这个视图解析器为前提
- 如果我们控制器方法返回的视图名没有前缀,那么最后得到的就是ThymeleafView
- 主要流程:
- 视图名被SpringMVC配置的视图解析器解析
- 视图名通过拼接视图前缀和后缀后得到最终路径
- 最后通过转发的方式实现跳转
我们之前练习的一直都是 Thymeleaf 的视图
@RequestMapping("/testThymeleafView")
public String testThymeleafView(){
return "success";
}
可以看到控制器方法返回时没有任何前缀,我们获得的就是ThymeleafView
如果想进行测试可以在我们的首页写一条超链接,请求地址为
/testThymeleaf
,运行后点击超链接就可以查看效果
$ 转发视图
-
在SpringMVC中默认的转发视图为 InternalResourceView 【网络资源视图】
-
当我们为控制器方法返回的视图名添加 forward: 前缀,得到的就是 InternalResourceView
-
这种视图不会通过核心配置文件中的视图解析器解析,而是将前缀后面的路径作为最终路径通过转发的方式实现跳转
-
转发可以转发到一个页面,也可以转发到一个请求上
主页编写发起请求的超链接
<a th:href="@{/testForward}">测试InternalResourceView</a><br>
控制器实现具体的跳转方法,此处我们跳转到/testThymeleafView请求上,因为我们的html页面的位置浏览器访问不到
@RequestMapping("/testForward")
public String testForward(){
return "forward:/testThymeleafView";
}
- 注意:
- 因为我们转发到一个 /testThymeleafView 请求上
- 所以我们先生成的是 InternalResourceView
- 后生成的是 ThymeleafView
- 尽管我们是跳到 /testThymeleafView 请求上进一步获得页面的
- 但是我们的转发地址栏显示testForward,页面是success
- 因为我们转发到一个 /testThymeleafView 请求上
$ 重定向视图
- SpringMVC中默认的重定向视图是 RedirectView
- 与转发视图使用方式类似,只是将前缀替换为 redirect:
- 通过重定向的方式实现跳转
- 重定向视图在解析时,会判断剩余部分是否以正斜杠 / 开头,若是则会自动拼接上下文路径
我们直接重定向到 /testForward 请求上去
@RequestMapping("/testRedirect")
public String testRedirect(){
return "redirect:/testForward";
}
发起请求页要写一个超链接
<a th:href="@{/testRedirect}">测试RedirectView</a>
- 对于重定向来说,重定向后的地址拼接上上下文就是最后页面地址栏中的地址
- 重定向和转发有什么区别呢?
- 浏览器请求次数不同
- 转发:当浏览器收到请求后,完成响应跳转到另一个地址
- 重定向:浏览器向服务器发送一个请求收到响应后,再向一个新地址发送请求
- 跳转地址不同
- 转发:只能在本站点资源内进行跳转
- 重定向:可以跳转到任意的地址 【其他站点】
- 地址栏显示不同:
- 转发:地址栏不会变化
- 重定向:地址栏会发生变化
- 数据共享规则不同:
- 转发:在一次请求中共享数据
- 重定向:在两次请求中不共享数据
- 发生行为不同
- 转发:服务器行为
- 重定向:客户端行为
- 浏览器请求次数不同
$ 视图控制器
- 是一种可以代替控制器方法实现简单页面跳转的方式
- 简单体现在请求直接返回一个视图名,没有啥其他业务功能
我们可以在springMVC的核心配置文件中进行声明
<!--尽管此处success报错,但是不影响使用:配置了这个后控制器中的方法就会失效-->
<!--我当前想到的作用就是将上下文路径定位到一个页面-->
<mvc:view-controller path="/success" view-name="success"></mvc:view-controller>
-
这个标签有两个常用的属性:
- path 代表我们的请求地址
- view-name 代表我们要跳转的视图名
-
当我们设置了这个标签后,控制器里的所有方法都会失效
- 我们需要开启 mvc 的注解驱动才能解决这个问题
<mvc:annotation-driven />
- 根据使用情景不同这个注解驱动还有很多其他作用
-
在此之前我们一直都是使用的都是html页面进行演示,如果是jsp文件,我们又将如何处理呢?
$ 使用JSP
- JSP 本身就是一个Servlet,可以直接访问,所以我们不需要去设置首页了
- JSP 中只存在转发视图和重定向视图
- 需求:我们要通过一个 jsp 模块演示如何显示 jsp 文件的视图
我们新建一个模块,然后将打包方式设置为 war,然后导入依赖,添加web模块,添加xml文件
在 web.xml 中依旧注册解决乱码问题的过滤器和前端控制器 Dispatcher
对于springMVC的核心配置文件所有变化,我们不在使用之前的视图解析器,而是替换为 InternalResourceViewResolver
<?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:context="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">
<!--扫描组件-->
<context:component-scan base-package="com.atguigu.mvc.controller"/>
<!--
在jsp中,不设置任何前缀自身也是一个转发视图,所以直接采用InternalResolver解析器
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--也需要我们指定前缀和后缀-->
<property name="prefix" value="/WEB-INF/templates/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
在 webapp 目录下,我们编写 index.jsp 文件
-
上面我们了解到当前 jsp 页面就是一个最小的域对象 pageContext
-
jsp 页面中动态获取上下文路径 pageContext.request.contextPath【使用EL表达式】
-
那么什么是 EL 表达式呢?
- 全称 Expression Language,语法格式 ${表达式},我们将其使用在jsp页面中,表达式通过为域对象的key
- 代替 JSP 进行数据的输出,只能用来获取数据,如果存在多个域对象,那么从低级向高级域搜索【先从pageContext查找key】
<%--
Created by IntelliJ IDEA.
User: npc
Date: 2022/11/23
Time: 17:37
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>第一个使用jdp的springMVC模块</title>
</head>
<body>
<h1>首页</h1>
<a href="${pageContext.request.contextPath}/success">点击跳转我们指定的jsp页面</a>
</body>
</html>
编写我们请求跳转后的页面 success.jsp
<%--
Created by IntelliJ IDEA.
User: npc
Date: 2022/11/23
Time: 17:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>成功</h1>
</body>
</html>