【笔记】SpringMVC学习笔记

前言

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning.(官网

利用Maven创建Web项目

传送门

添加依赖

pom.xml
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

定义Controller类

src/main/java/com/controller/UserController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

@RequestMapping("/method")
@ResponseBody
public String method() {
return "{'key':'value'}";
}
}

创建SpringMVC容器配置类

  • 将Controller类交给SpringMVC容器管理
src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
package com.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.controller")
public class SpringMvcConfig {
}

创建Servlet配置类

继承子类(用于简化开发)

  • 创建Servlet配置类,继承AbstractAnnotationConfigDispatcherServletInitializer类,加载SpringMVC的配置类
src/main/java/com/conf/ServletContainersInitConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.conf;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

// 加载Spring容器的配置
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

// 加载SpringMVC容器的配置
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

// 设置归SpringMVC管理的请求范围
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

继承父类(用于学习底层)

  • 创建Servlet配置类,继承AbstractDispatcherServletInitializer类,加载SpringMVC的配置类
src/main/java/com/conf/ServletContainersInitConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.conf;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

// 加载SpringMVC容器的配置
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringMvcConfig.class);
return applicationContext;
}

// 设置归SpringMVC管理的请求范围
protected String[] getServletMappings() {
return new String[]{"/"};
}

// 加载Spring容器的配置
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}

放行静态页面访问请求

创建SpringMvcSupport配置类

  • 继承WebMvcConfigurationSupport类,重写addResourceHandlers()方法和addInterceptors()方法

addResourceHandler("/pages/**", "/pages/"):当访问的资源路径为/pages/**时,访问静态路径/pages/下的资源

src/main/java/com/conf/SpringMvcSupport.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.conf;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**", "/pages/");
registry.addResourceHandler("/css/**", "/pages/");
registry.addResourceHandler("/js/**", "/pages/");
}
}

在SpringMVC容器配置类添加包扫描范围

src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
10
package com.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan({"com.controller", "com.conf"})
@EnableWebMvc
public class SpringMvcConfig {
}

与Spring容器整合

创建Spring容器配置类

  • 因为Controller类已经交给了SpringMVC容器管理,所以在Spring容器配置类中排除对Controller的bean管理

@ComponentScan():指定包扫描

value = "":指定扫描的包
excludeFilters = @ComponentScan.Filter():指定排除过滤器

type:过滤器类型

FilterType.ANNOTATION:根据注解过滤
FilterType.REGEX:根据正则表达式过滤
FilterType.CUSTOM:根据用户自定义方式过滤

classes:如果过滤类型是根据注解过滤,可以通过classes指定过滤的注解类型

src/main/java/com/conf/SpringConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(
value = "com",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {

}

不将SpringMvcConfig类作为配置类

  • 因为Controller已经交给了SpringMVC容器管理,为了防止Spring容再次管理Controller,需要注释SpringMVC容器配置类中的@Configuration注解
src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
package com.conf;

import org.springframework.context.annotation.ComponentScan;

//@Configuration
@ComponentScan("com.controller")
public class SpringMvcConfig {
}

让tomcat服务器启动时加载Spring容器

  • 在Servlet配置类中同时加载Spring容器
src/main/java/com/conf/ServletContainersInitConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.conf;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

// 加载SpringMVC容器的配置
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringMvcConfig.class);
return applicationContext;
}

// 设置归SpringMVC管理的请求范围
protected String[] getServletMappings() {
return new String[]{"/"};
}

// 加载Spring容器的配置
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringConfig.class);
return applicationContext;
}
}

过滤器

解决POST请求的中文乱码

  • 在Servlet配置类中添加getServletFilters()过滤器配置方法,利用过滤器解决POST请求的中文乱码
src/main/java/com/conf/ServletContainersInitConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.conf;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.Filter;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

// 加载SpringMVC容器的配置
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringMvcConfig.class);
return applicationContext;
}

// 设置归SpringMVC管理的请求范围
protected String[] getServletMappings() {
return new String[]{"/"};
}

// 加载Spring容器的配置
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SpringConfig.class);
return applicationContext;
}

// 添加过滤器配置
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[]{characterEncodingFilter};
}
}

开启JSON请求转换对象接收

  • 在SpringMVC配置类上添加@EnableWebMvc注解
src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
package com.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@ComponentScan("com.controller")
@EnableWebMvc
public class SpringMvcConfig {
}

处理请求

处理任意方法请求

1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "";
}

处理指定方法请求

1
2
3
4
5
@RequestMapping(value = "/", method = RequestMethod.GET)
public String method() {
...
return "";
}
1
2
3
4
5
@GetMapping
public String method() {
...
return "";
}

获取请求参数

  • 请求参数名与形参名相同时,可以自动进行映射

获取query请求参数

  • 通过@RequestParam("")标注的形参为query请求参数
  • 如果形参没有注解标注,则默认为query请求参数

基本类型

@RequestParam(""):指定请求中的参数名,如果请求参数名与形参名相同,可以省略

value = "":指定请求参数名
required = true:是否为必传的参数
defaultValue = "":指定参数默认值

1
2
3
4
5
@RequestMapping("/")
public String method(@RequestParam("") int id, String name) {
...
return "";
}

实体类

  • 首先定义一个实体类,实体类中的属性名与请求参数名保持相同,并定义相关get、set、toString方法
src/main/java/com/pojo/User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pojo;

public class User {

Integer id;
String name;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
1
2
3
4
5
@RequestMapping("/")
public String method(User user) {
...
return "";
}

数组

  • 当相同参数名的请求值有多个的时候,可以使用数组进行接收
  • 也可以使用字符串类型强制接收所有参数值,默认使用逗号分隔
1
2
3
4
5
@RequestMapping("/")
public String method(String[] name) {
...
return "";
}

集合

  • 当相同参数名的请求值有多个的时候,可以使用集合进行接收
  • 接收集合类型的请求时,必须要添加@RequestParam注解
1
2
3
4
5
@RequestMapping("/")
public String method(@RequestParam List<String> name) {
...
return "";
}

日期类型

  • 默认日期格式化方式为yyyy/MM/dd
1
2
3
4
5
6
@RequestMapping("/")
public String method(Date date) {
System.out.println(date.toLocaleString());
...
return "";
}
重新指定日期格式化方式
1
2
3
4
5
6
@RequestMapping("/")
public String method(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
System.out.println(date.toLocaleString());
...
return "";
}
重新指定所有日期格式化方式
  • 添加SpringMVC自定义日期格式转换器,将SpringMVC默认以/分隔改为以-分隔
1
2
3
4
@InitBinder
public void InitBinder (ServletRequestDataBinder binder) {
binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), true));
}

获取body请求参数

  • 通过@RequestBody标注的形参为body请求参数

实体类

src/main/java/com/pojo/User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pojo;

public class User {

Integer id;
String name;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
1
2
3
4
5
@RequestMapping("/")
public String method(@RequestBody User user) {
...
return "";
}

集合

1
2
3
4
5
@RequestMapping("/")
public String method(@RequestBody List<String> name) {
...
return "";
}

获取path请求参数

  • 通过@PathVariable标注的形参为path请求参数
  • {}作为参数占位符

@PathVariable:在请求路径传参

1
2
3
4
5
@RequestMapping("/{name}")
public String method(@PathVariable String name) {
...
return "";
}

处理响应

只跳转页面

  • 以后我们写代码可以单独写TemplatePageController用于处理页面跳转

配置前端页面访问路径的前后缀

  • 不配置时默认使用以下缺省值
1
2
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

返回字符串(常用)

  • 通过返回的字符串(string),根据prefix+string+suffix进行页面跳转
1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "";
}
转发和重定向
转发到本项目
1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "index";
}
转发到其他位置
  • 返回值加forward:前缀
1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "forward:/index";
}
目标重定向
重定向到站内
  • 在SpringMVC中目标重定向也可以通过Model传递参数
  • 返回值加redirect:前缀
1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "redirect:/test";
}
重定向到站外
1
2
3
4
5
@RequestMapping("/")
public String method() {
...
return "redirect:/http://127.0.0.1:8080/";
}

只响应数据

  • 以后我们写代码可以单独写JsonObjectController用于响应数据

  • @ResponseBody注解标注,ModelAndView会自动将返回值转换为json格式字符串

返回Map对象(常用)

1
2
3
4
5
6
7
@RequestMapping("/")
@ResponseBody
public Map<String, Object> method() {
Map<String, Object> map = new HashMap<>();
map.put(<key>, <value>);
return map;
}

返回引用类型对象

src/main/java/com/pojo/User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pojo;

public class User {

Integer id;
String name;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
1
2
3
4
5
6
7
8
@RequestMapping("/")
@ResponseBody
public User method() {
User user = new User();
user.setId(1);
user.setName("");
return user;
}

返回值为空

  • 将数据存储在Map对象,将Map对象转换为json格式字符串
  • 通过HttpServletResponse对象,响应数据到客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping("/")
public void method(HttpServletResponse response) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put(<key>, <value>);
// 将map中的数据转换为json格式字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(map);
// 设置响应数据的编码
//response.setCharacterEncoding("utf-8");
// 告诉客户端相应数据类型为text/html,编码为utf-8,请以这种编码形式进行数据呈现
response.setContentType("text/html;charset=utf-8");
// 将字符串响应到客户端
response.getWriter().println(jsonStr);
}

既响应数据,又跳转页面

  • 以后我们写代码可以单独写ModelAndViewController用于同时页面跳转并响应数据

返回ModelAndView对象(常用)

  • 返回值会交给DispatcherServletd对象进行处理
  • DispatcherServlet对象会调用viewresolver对结果进行解析
  • 基于viewresolver找到对应的view页面(prefix+viewname+suffix)
  • 将model中的数据填充到view页面上
  • 返回一个带有model数据的页面给DispatcherServlet
  • DispatcherServlet将带有model数据的页面响应到客户端
1
2
3
4
5
6
7
@RequestMapping("/")
public ModelAndView method() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("");
modelAndView.addObject(<key>, <value>);
return modelAndView;
}

返回字符串

  • 通过Model对象传输数据,将数据填充到页面上
  • 通过返回的字符串(string),根据prefix+string+suffix进行页面跳转

<key>:键,仅可以字符串类型
<value>:值,可以任意类型

1
2
3
4
5
6
@RequestMapping("/")
public String method(Model model) {
model.addAttribute(<key>, <value>);
...
return "";
}

拦截器

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用
    • 在指定的方法调用前后执行预先设定的代码
    • 终止原始方法的执行
  • 拦截器与过滤器的区别
    • 归属不同:拦截器属于SpringMVC的技术,过滤器属于Servlet的技术
    • 拦截内容不同:拦截器仅对SpringMVC进行增强,过滤器对所有访问进行增强

创建拦截器类

  • 如果preHandle()方法返回false,表示拦截,则原始操作及其之后的操作都不执行;如果preHandle()方法返回true,表示放行,则原始操作及其之后的操作都正常执行
  • 形参handler可以通过反射获取原始操作的对象
src/main/java/com/controller/interceptor/UserInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserInterceptor implements HandlerInterceptor {

// 原始操作之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle()");
return true;
}

// 原始操作之后执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle()");
}

// 所有操作完成之后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion()");
}
}

配置类

通过SpringMvcSupport配置类完成配置

创建SpringMvcSupport配置类
  • 继承WebMvcConfigurationSupport类,重写addResourceHandlers()方法和addInterceptors()方法
  • 通过addResourceHandlers()方法配置放行的请求范围
  • 通过addInterceptors()方法配置拦截器及其管理的请求范围

addResourceHandler("/pages/**", "/pages/"):当访问的资源路径为/pages/**时,访问静态路径/pages/下的资源

src/main/java/com/conf/SpringMvcSupport.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.conf;

import com.interceptor.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

@Autowired
private UserInterceptor userInterceptor;

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}

@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor).addPathPatterns("/users", "/users/*);
}
}
在SpringMVC容器配置类添加包扫描范围
src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
10
package com.conf;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan({"com.controller", "com.interceptor", "com.conf"})
@EnableWebMvc
public class SpringMvcConfig {
}

直接通过SpringMvcConfig配置类完成配置(简化)

src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.conf;

import com.controller.interceptor.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan({"com.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

@Autowired
private UserInterceptor userInterceptor;

public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor).addPathPatterns("/user", "/users/*");
}
}

拦截器链

  • 由多个拦截器组成拦截器链

创建多个拦截器类

src/main/java/com/controller/interceptor/UserInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserInterceptor implements HandlerInterceptor {

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle()");
return true;
}

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle()");
}

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion()");
}
}
src/main/java/com/controller/interceptor/UserInterceptor2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserInterceptor2 implements HandlerInterceptor {

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle()");
return true;
}

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle()");
}

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion()");
}
}

引入多个配置

src/main/java/com/conf/SpringMvcConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.conf;

import com.controller.interceptor.UserInterceptor;
import com.controller.interceptor.UserInterceptor2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan({"com.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

@Autowired
private UserInterceptor userInterceptor;

@Autowired
private UserInterceptor2 userInterceptor2;

public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor).addPathPatterns("/user", "/users/*");
registry.addInterceptor(userInterceptor2).addPathPatterns("/user", "/users/*");
}
}

拦截器的执行顺序

  • 拦截器执行顺序根据addInterceptors()方法配置拦截器的顺序而排序

拦截器的执行顺序

当preHandle()返回true时
  • 拦截器的preHandle() -> 原始操作 -> 拦截器的postHandle() -> 拦截器的afterCompletion() -> 运行结束
当preHandle()返回false时
  • 拦截器的preHandle() -> 运行结束

拦截器链的执行顺序

当preHandle()返回true时
  • 拦截器1的preHandle() -> 拦截器2的preHandle() -> 拦截器3的preHandle() -> 原始操作 -> 拦截器3的postHandle() -> 拦截器2的postHandle() -> 拦截器1的postHandle() -> 拦截器3的afterCompletion() -> 拦截器2的afterCompletion() -> 拦截器1的afterCompletion() -> 运行结束
当userInterceptor3的preHandle()返回false时
  • 拦截器1的preHandle() -> 拦截器2的preHandle() -> 拦截器3的preHandle() -> 拦截器2的afterCompletion() -> 拦截器1的afterCompletion() -> 运行结束

完成

参考文献

哔哩哔哩——黑马程序员