概述
一、springMVC是spring的MVC模块,用来实现WEB功能
二、MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分,也就是说,使用springMVC,我们需要按照模型、视图、控制器来实现web功能
三、MVC:
- M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如Student、User等
一类称为业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
- V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
- C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
四、MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求(Controller调用service处理业务逻辑,service调用DAO操作数据库,DAO将数据库处理结果返回给service,service再返回给Controller),处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
五、SpringMVC是Spring为表述层开发提供的一整套完备的解决方案。
三层架构分为表述层(或表示层)、业务逻辑层、数据访问层
表述层表示前台页面和后台servlet,也就是说,前台页面发送请求到服务器中,服务器使用servlet接收请求处理请求,最终响应浏览器,SpringMVC就是来处理这一过程的
六、前台发送请求超链接、表单提交等,我们根据请求地址找到相对应的servlet,使用servlet的service处理请求,获取请求参数,调用service处理业务逻辑,处理完了之后会返回处理结果,如果是查询操作,会把查询结果放在指定的域对象中,然后我们根据不同的处理结果来响应浏览器,例如如果是登录功能,登陆成功我们展示登录成功的页面,登录失败我们重定向到登录页面让用户重新登录
HelloWorld
一、开发环境
二、创建maven工程:新建module
点击next,
点击finish,完成springMVC项目springMVC-demo1
的创建。
在POM.xml中配置打包文件为war包:<packaging>war</packaging>
,并配置依赖:
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
由于Maven的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
三、在maven工程中添加web模板:右击main,新建directory,命名为webapp
这样他就会在webapp下自动创建WEB-INF文件夹和web.xml文件
四、配置web.xml:注册SpringMVC的前端控制器DispatcherServlet
<!-- 因为是注册servlet,所以使用servlet标签 -->
<servlet>
<!-- servlet-name与servlet-mapping的servlet-name一致 -->
<servlet-name>springMVC</servlet-name>
<!-- 指定servlet全类名-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
/代表浏览器发送的不包括.jsp为后缀的所有请求
.jsp文件的本质是servlet,他需要服务器指定的servlet来处理,所以.jsp文件不需要DispatcherServlet处理
/*代表所有请求,包括.jsp的请求,但是这样的话,.jsp请求会被springMVC处理,springMVC会把他当成一个普通的请求来处理
而不会去找他相对应的jsp页面,那就找不到访问路径
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<url-pattern>
标签中使用/
和/*
的区别:
/
所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求,因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面/*
则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*
的写法
以上配置是默认配置,在这种配置下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为<servlet-name>-servlet.xml
,例如,以上配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml
,如果我们想要把配置文件要放在resource文件夹中,可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间
<init-param>
<!--
<param-name>contextConfigLocation</param-name>固定写法,
classpath:表示类路径下
-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
在resource文件夹下创建springMVC.xml文件:
以后,springMVC.xml文件就是我们springmvc的配置文件
五、创建请求控制器:由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法。因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在。新建src/main/java/com/atguigu/mvc/controller/HelloController.java
文件,代码如下:
@Controller
public class HelloController {}
六、配置springMVC的配置文件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: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"></context: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>
七、测试HelloWorld,
- 配置tomcat:
如果没有artifact,说明你pom.xml中没有配war打包方式
上下文路径就是浏览器中访问的路径localhost:8080后面那部分
点击ok即可 - 实现对首页的访问,在请求控制器中创建处理请求的方法:@RequestMapping注解用于处理请求和控制器方法之间的映射关系,其value属性可以通过请求地址匹配请求,
/
表示的当前工程的上下文路径localhost:8080/springMVC/
@Controller
public class HelloController {
// 通过@RequestMapping注解,可以通过请求路径匹配要处理的具体的请求
// 当请求路径是/时,会执行下面这个方法,下面这个方法返回的视图名称加上你在springMVC.xml中配置的视图前缀、视图后缀
// 就可以跳转到src/main/webapp/WEB-INF/templates/index.html这个页面
// @RequestMapping(value="/")
@RequestMapping("/")// 如果是个value赋值,value可以省略不写
public String index(){// 这个方法名叫啥其实无所谓,没有影响
return "index";
}
}
- 通过超链接跳转到指定页面
(1)在主页index.html中设置超链接:
<!DOCTYPE html>
<!--xmlns:th="http://www.thymeleaf.org"是thymeleaf的命名空间,加了这段代码才能在body中使用thymeleaf语法-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<!--/target表示绝对路径,绝对路径分为浏览器解析的、服务器解析的,超链接中的绝对路径就是由浏览器解析的,他会从localhost:8080下访问-->
<!--<a href="/target">访问目标页面target.html</a>-->
<!--th:href加上th:前缀,这个属性会被thymeleaf解析,thymeleaf检测到{}中时绝对路径时,他会自动在绝对路径前面加上上下文路径-->
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
</html>
(2)在请求控制器中创建处理请求的方法
@Controller
public class HelloController {
@RequestMapping("/")// 如果是个value赋值,value可以省略不写
public String index(){
return "index";
}
@RequestMapping("/target")
public String toTarget(){
return "target";
}
}
总结:浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
@RequestMapping注解
一、新建springMVC项目springMVC-demo2
,在pom.xml中引入依赖,创建webapp文件夹,并生成WEB-INF文件夹和web.xml文件,在其中注册前端控制器DispatcherServlet,创建配置文件springMVC.xml并配置thymeleaf的视图解析器,接下来就是对HTML页面和controller的编写
二、@RequestMapping
注解的作用就是将请求和处理请求的控制器方法关联
起来,建立映射关系。SpringMVC接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
三、如果我们有两个controller,在两个controller中,都给某个方法配置了@RequestMapping("/")
,那么springMVC会报错,不能配置值一样的@RequestMapping
四、@RequestMapping注解的属性
@RequestMapping注解的位置
一、首先匹配标识在类上的@RequestMapping注解,然后匹配标识在方法上的@RequestMapping注解
- @RequestMapping标识一个类:设置映射请求的请求路径的初始信息
- @RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@Controller
@RequestMapping("/test")
public class RequestMappingController {
//此时请求映射所映射的请求的请求路径为:/test/testRequestMapping
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
return "success";
}
}
二、如果项目中模块比较多,就可以把@RequestMapping标识在类上,表示某一个模块
@RequestMapping注解的value属性
一、@RequestMapping注解的value属性通过请求的请求地址匹配请求映射,他是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求
@RequestMapping(
value = {"/testRequestMapping", "/test"}
)
// 请求路径为/testRequestMapping或/test则执行下面的方法,value数组中只要有一个路径匹配成功就执行下面的方法
public String testRequestMapping(){
return "success";
}
二、@RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射
@RequestMapping注解的method属性
一、@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射。该属性是一个RequestMethod类型的数组,表示该请求映射能够匹配
多种请求方式的请求
@RequestMapping(
value = {"/testRequestMapping", "/test"},
method = {RequestMethod.GET}
)
public String testRequestMapping(){
return "success";
}
二、先判断请求路径是否满足value指定的值,满足才判断是否满足指定的请求方法,若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错:405:Request method 'POST' not supported
三、如果不指定method属性那么默认不限制请求方式
四、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
public class RequestMappingController {
// 直接在()中写value值就可以了
// 当请求路径为/testGetMapping,请求方法为get时,会执行下面这个方法
@GetMapping("/testGetMapping")
public String testGetMapping(){
return "success";
}
}
五、常用的请求方式有get,post,put,delete,但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理,若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter,在RESTful部分会讲到
@RequestMapping注解的params属性
一、@RequestMapping注解的params属性通过请求的请求参数匹配请求映射,该属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系,请求参数必须要全部满足params属性的规定才会执行方法:
“param”:要求请求映射所匹配的请求必须携带param请求参数
“!param”:要求请求映射所匹配的请求必须不能携带param请求参数
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
@RequestMapping(
value = {"/testRequestMapping", "/test"},
method = {RequestMethod.GET, RequestMethod.POST},
params = {"username","password!=123456"}
// 参数必须有username,但是password的值不能为123456才会执行下面的函数
)
public String testRequestMapping(){
return "success";
}
二、若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400:Parameter conditions "username, password!=123456" not met for actual request parameters: username={admin}, password={123456}
@RequestMapping注解的headers属性
一、@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射,该属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系,请求的请求头信息必须要全部满足headers属性的规定才会执行方法:
“header”:要求请求映射所匹配的请求必须携带header请求头信息
“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
“header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value
二、若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到
@RequestMapping(
value = "/testParamsAndHeaders",
params = {"username","password!=123456"},
headers = {"Host=localhost:8080"}
)
public String testParamsAndHeaders(){
return "success";
}
SpringMVC支持ant风格的路径
?
:表示任意的【单个】字符,除?
、/
等特殊字符
*
:表示任意的【0个或多个】字符,除?
、/
等特殊字符
**
:表示任意的一层或多层目录
注意:在使用**
时,只能使用/**/xxx
的方式
//@RequestMapping("/a?a/testAnt")
//@RequestMapping("/a*a/testAnt")
@RequestMapping("/**/testAnt")
public String testAnt(){
return "success";
}
SpringMVC支持路径中的占位符
一、原始方式:/deleteUser?id=1
rest方式:/deleteUser/1
二、SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping
注解的value属性中通过占位符{xxx}
表示传输的数据,在通过@PathVariable
注解,将占位符所表示的数据赋值给控制器方法的形参
@RequestMapping("/testRest/{id}/{username}")
// @PathVariable("id")Integer id, @PathVariable("username") String username:
// 将占位符id的值(url传过来的id值)自动赋值给形参Integer id
// 将占位符username的值(url传过来的username值)自动赋值给形参String username
public String testRest(@PathVariable("id") String id,@PathVariable("username")
String username){
System.out.println("id:"+id+",username:"+username);
return "success";
}
//最终输出的内容为-->id:1,username:admin
三、如果@RequestMapping
设置的路径中有占位符,那么请求路径中必须传参
SpringMVC获取请求参数
通过ServletAPI获取
一、将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象,testServletAPI是DispatcherServlet调用的,DispatcherServlet可以根据控制器方法的形参类型来为形参注入不同的值,若DispatcherServlet检测到方法形参是HttpServletRequest,他就会将DispatcherServlet所获得的表示当前请求的request对象赋值给request参数,所以这个request参数就是当前请求
@RequestMapping("/testServletAPI")
// 形参位置的request表示当前请求
// HttpServletRequest request 请求对象
public String testServletAPI(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
二、这种方式获取不到通过占位符方式传过来的参数
三、如果传过来的有多个同名参数,那么只能获取到第一个参数,可以通过request.getParameterValues("username");
获得字符串类型的数组,里面包含所有的参数
通过控制器方法的形参获取请求参数
只要保证形参中的参数名和请求参数的名字保持一致就可以自动的将请求参数赋值给对应的形参
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "success";
}
如果传过来的有多个同名参数,怎么办?
- 通过字符串接收,同名参数会以
,
分割
@RequestMapping("/testParam")
public String testParam(String username, String password, string hobby){
System.out.println("username:"+username+",password:"+password,"hobby:"+hobby);
return "success";
}
// username:admin,password:123,hobby:a,b,c
- 通过字符串数组接收,同名参数放在数组中
@RequestMapping("/testParam")
public String testParam(String username, String password, string hobby){
System.out.println("username:"+username+",password:"+password,"hobby:"+Arrays.toString(hobby));
return "success";
}
// username:admin,password:123,hobby:[a,b,c]
总结:若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数,若使用字符串数组类型的形参,此参数的数组中包含了每一个数据,若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
@RequestParam
一、@RequestParam是将请求参数和控制器方法的形参创建映射关系,也就是你要拿着哪个请求参数去对应哪个形参
二、@RequestParam注解一共有三个属性:
value
:指定为形参赋值的请求参数的参数名required
:设置是否必须传输此请求参数,默认值为true
,要求当前请求必须传输value
所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue
属性,则页面报错400:Required String parameter 'xxx' is not present;
。若设置为false,则当前请求不是必须传输value
所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue
:不管required
属性值为true
或false
,当value
所指定的请求参数没有传输或传输的值为""
时,则使用默认值为形参赋值
@RequestMapping("/testParam")
public String testParam(
@RequestParam(value = "user_name", required = false, defaultValue = "hehe") String username,// 会把请求路径中的user_name参数自动赋值给形参username
String password,
String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "success";
}
@RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系,一共有三个属性:value、required、defaultValue,用法同@RequestParam
@RequestMapping("/testParam")
public String testParam(@RequestHeader(value = "host", required = true, defaultValue = "haha") String host){// 从请求头中找到host,将值传递给形参host
System.out.println("host:"+host);
return "success";
}
@CookieValue
一、@CookieValue是将cookie数据和控制器方法的形参创建映射关系,一共有三个属性:value、required、defaultValue,用法同@RequestParam
@RequestMapping("/testParam")
public String testParam(@CookieValue("JSESSIONID") String JSESSIONID){
System.out.println("JSESSIONID:"+JSESSIONID);
return "success";
}
二、通过HttpSession session = request.getSession();
可以生成一个键为JsessionID的cookie
通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
实体类代码:
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String sex;
private String email;
public User() {}
public User(Integer id, String username, String password, Integer age, String sex, String email) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public String getSex() {return sex;}
public void setSex(String sex) {this.sex = sex;}
public String getEmail() {return email;}
public void setEmail(String email) {this.email = email;}
}
传参:
<form th:action="@{/testpojo}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
性别:<input type="radio" name="sex" value="男">男<input type="radio" name="sex" value="女">女<br>
年龄:<input type="text" name="age"><br>
邮箱:<input type="text" name="email"><br>
<input type="submit">
</form>
映射:
@RequestMapping("/testpojo")
public String testPOJO(User user){
System.out.println(user);
return "success";
}
出现乱码
解决获取请求参数的乱码问题
一、出现乱码:字符编码不一致
二、在设置请求对象的编码之前,已经获取了某个请求参数,那么设置的编码是无效的。在本例中,DispatcherServlet获取请求参数在前,如果在映射中设置编码方法那么是无效的,所以我们需要在DispatcherServlet获取请求参数前设置编码方式,谁在servlet之前执行呢?监听器servletContextListener加载时间最早,然后是过滤器filter,最后才是servlet,监听器servletContextListener用来监听servlet的创建和销毁,只要设置了过滤路径,当前所访问的请求地址满足过滤路径,都会被过滤器过滤,所以我们应该用过滤器来设置编码,我们每次先交给过滤器处理,处理完了再交给DispatcherServlet处理
三、乱码有两种,:get请求的乱码、post请求的乱码
四、如果我们把上述请求改为get请求,则不会出现乱码。
这是因为get请求出现乱码是由tomcat造成的,在tomcat配置文件中
添加URIEncoding="UTF-8"
就不会出现乱码了
五、使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册
<!--配置springMVC的编码过滤器-->
<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中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
域对象共享数据
正常处理一个请求的过程:设置编码、获取请求参数、将请求参数作为条件调用servlet处理业务逻辑,service会调用DAO访问数据库,DAO将操作结果返回给service,service再返回给控制层,如果有数据要发送给页面,那我们就需要将数据在域对象中共享,
servletContext:服务器开启到服务器关闭,即整个应用的范围,这个对象只在服务器开启时创建,服务器关闭时销毁,这个对象从头到尾只创建一次,这就是我们能在域对象中共享数据的原因,你用的对象就是同一个。通过转发可以获取请求域中的数据,因为转发属于一次请求。为什么能在会话中共享数据,因为只要cookie存在,你创建的相应的session永远是同一个
session:浏览器开启到浏览器关闭,session分为钝化和活化:服务器关闭,浏览器没关闭,会话仍然在继续,此时哦我们存储在session中的数据会经过序列化,序列化到我们的磁盘上,这就叫钝化。如果我们的浏览器仍然没有关闭,但是服务器开启了,此时会将我们钝化之后的内容,重新读取到session中,这就叫做活化
新建项目springMVC-demo3
向request域对象共享数据
注意:共享的数据键是字符串,值是对象
使用ServletAPI向request域对象共享数据
- 新建
src/main/java/com/atguigu/mvc/controller/ScopeController.java
,在控制器中添加共享数据
@Controller
public class ScopeController {
//使用servletAPI向request域对象共享数据
@RequestMapping("/testRequestByServletAPI")
public String testRequestByServletAPI(HttpServletRequest request){
// setAttribute添加共享数据:request.setAttribute("键", "值");
request.setAttribute("testRequestScope", "hello,servletAPI");
return "success";// 从/testRequestByServletAPI转发到success.html,WEB-INF下面的资源重定向访问不了,
}
}
- 新建
src/main/webapp/WEB-INF/templates/success.html
,在其中获取数据
<body>
<!--如果访问的是request域中的数据,直接通过键名testRequestScope获取值,-->
<p th:text="${testRequestScope}"></p>
</body>
使用ModelAndView向request域对象共享数据
ModelAndView是SpringMVC提供的对象,他有Model和View的功能,Model主要用于向请求域共享数据,View主要用于设置视图,实现页面跳转
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView mav = new ModelAndView();
//处理模型数据,即向请求域request共享数据:mav.addObject("键", "值");
mav.addObject("testRequestScope", "hello,ModelAndView");
//设置视图名称:mav.setViewName("视图名称");
mav.setViewName("success");
return mav;
}
注意:返回值必须是ModelAndView,需要将ModelAndView交给DispatcherServlet,DispatcherServlet才能解析他
获取数据:
<body>
<!--如果访问的是request域中的数据,直接通过键名testRequestScope获取值,-->
<p th:text="${testRequestScope}"></p>
</body>
使用Model向request域对象共享数据
用法和ServletAPI很像
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope", "hello,model");
System.out.println(model.getClass().getName());
return "success";
}
使用map向request域对象共享数据
在形参的位置创建一个map类型的数据,向map中存储的数据就是我们向request域中存储的数据
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){ // 注意:共享的数据键是字符串,值是对象
map.put("testRequestScope", "hello,map");
System.out.println(map.getClass().getName());
return "success";
}
使用ModelMap向request域对象共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope", "hello,ModelMap");
// modelMap.getClass()获取class对象,.getName()获得当前类的全名
System.out.println(modelMap.getClass().getName());
return "success";
}
Model、ModelMap、Map的关系
Model、ModelMap、Map类型的参数其实本质上都是BindingAwareModelMap
类型的
向session域共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope", "hello,session");
return "success";
}
获取数据:
<body>
<!--如果访问的是session域中的数据,直接通过session.键名获取值-->
<p th:text="${session.testSessionScope}"></p>
</body>
向application域共享数据
application域指的是servletContext域,如何获得servletContext对象?
- 在JSP中,范围是当前整个JSP页面的域对象pageContext中可以获取
- request、session可以获取
- servlet的初始化方法init方法中的servletConfig对象获取,servletConfig对象中有当前servlet的配置信息,可以通过servletConfig对象获取当前servlet的名称,即注册时servlet-name的标签值,获取当前servlet的初始化参数,获取当前servlet的servletContext对象
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();// 获取servletContext对象
application.setAttribute("testApplicationScope", "hello,application");// 向域中添加数据
return "success";
}
获取数据:
<body>
<!--如果访问的是servletContext域中的数据,直接通过application.键名获取值,-->
<p th:text="${application.testApplicationScope}"></p>
</body>
除非是当前整个工程需要共享的数据我们才会放在servletContext域中,session用来保存用户的登录状态