filter过滤器依赖于servlet容器,而interceptor依赖于spring容器
本项目在springboot里使用(filter)过滤器和(interceptor)拦截器,创建一个springboot项目(版本2.3.7),相关依赖:
4.0.0
com.example
demo
0.0.1-SNAPSHOT
demo
Demo project for Spring Boot
1.8
UTF-8
UTF-8
2.3.7.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
1.8
UTF-8
org.springframework.boot
spring-boot-maven-plugin
2.3.7.RELEASE
com.example.demo.DemoApplication
repackage
repackage
实现filter过滤器的方法:
自定义类实现javax.servlet.Filter接口,该接口定义了三个方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javax.servlet;
import java.io.IOException;
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
//主要实现此方法即可,该方法最终调用filterChain.doFilter(servletRequest,servletResponse)则放行,不调用则拦截
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
一、@Component注解版(配合@Order注解在多过滤器环境下可设置优先级,数字越小越优先)
1、自定义MyFilter1、MyFilter2、MyFilter3类实现javax.servlet.Filter接口
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@Component
@Order(3)
public class MyFilter1 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 1");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 1");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@Component
@Order(2)
public class MyFilter2 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 2");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@Component
@Order(1)
public class MyFilter3 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 3");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 3");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
2、自定义FilterController类
package com.example.demo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author jiang
* @date 2022/10/19 16:05
*/
@RestController
public class FilterController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping("/hello")
public String hello(){
String str = "hello";
logger.info(str);
return str;
}
@RequestMapping("/bye")
public String bye(){
String str = "bye";
logger.info(str);
return str;
}
}
3、application.properties默认
# 应用名称
spring.application.name=demo
# 应用服务 WEB 访问端口
server.port=8080
4、启动项目
5、postman访问http://localhost:8080/hello
注释掉@Order注解后
默认按照过滤器名称字符排序来执行过滤链
二、@WebFilter+@ServletComponentScan注解(无法设置优先级,但是可以设置过滤规则)
1、注释掉@Component和@Order,给过滤器添加@WebFilter注解并设置过滤URL,给启动类设置@ServletComponentScan注解
Filter
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@WebFilter(urlPatterns = "/hello")
//@Component
//@Order(3)
public class MyFilter1 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 1");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 1");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@WebFilter(urlPatterns = "/bye")
//@Component
//@Order(2)
public class MyFilter2 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 2");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@WebFilter
//@Component
//@Order(1)
public class MyFilter3 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 3");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 3");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
启动类
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan//扫描servlet提供注解
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2、postman访问http://localhost:8080/hello
3、注释掉MyFilter2里doFilter()方法的filterChain.doFilter(servletRequest,servletResponse);即中断请求不放行,通过ServletResponse返回数据给用户,将@WebFilter过滤规则删除,默认所有请求过滤
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
@WebFilter
//@Component
//@Order(2)
public class MyFilter2 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 2");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
// filterChain.doFilter(servletRequest,servletResponse);
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
httpServletResponse.setCharacterEncoding("UTF-8");
PrintWriter pw = httpServletResponse.getWriter();
pw.write("请求未通过");
pw.flush();
pw.close();
}
@Override
public void destroy() {
}
}
请求未通过,因为在Myfilter2里未放行,所以未执行MyFilter3过滤器
三、通过Java配置类注册过滤器
1、将MyFilter1、MyFilter2、MyFilter3的@WebFilter、@Component、@Order注解注释掉
2、创建FilterConfig配置类,并通过FilterRegistrationBean设置优先级和过滤规则
package com.example.demo.config;
import com.example.demo.filter.MyFilter1;
import com.example.demo.filter.MyFilter2;
import com.example.demo.filter.MyFilter3;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author jiang
* @date 2022/10/21 17:03
*/
@Configuration
public class FilterConfig {
/*
* 若只配置自定义过滤器Bean,则执行顺序按照配置先后顺序执行,即2--》3--》1
* */
@Bean
public MyFilter2 getMyFilter2(){
return new MyFilter2();
}
@Bean
public MyFilter3 getMyFilter3(){
return new MyFilter3();
}
@Bean
public MyFilter1 getMyFilter1(){
return new MyFilter1();
}
/*
* 若配置了FilterRegistrationBean注入自定义过滤器,则按照FilterRegistrationBean配置顺序执行过滤器,即1--》3--》2
* */
@Bean
public FilterRegistrationBean getFilterRegistrationBean1(MyFilter1 myFilter1){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(myFilter1);
//filterRegistrationBean对象提供方法设置优先级,则以此为准,数字越小,优先级越高,当设置数字相同时,依然按照配置顺序执行
filterRegistrationBean.setOrder(3);
//设置过滤URL
filterRegistrationBean.addUrlPatterns("/hello");
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean getFilterRegistrationBean3(MyFilter3 myFilter3){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(myFilter3);
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/hello");
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean getFilterRegistrationBean2(MyFilter2 myFilter2){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(myFilter2);
filterRegistrationBean.setOrder(2);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
3、取消注释MyFilter2#doFilter()里的filterChain.doFilter(servletRequest,servletResponse);并注释掉响应数据代码
package com.example.demo.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author jiang
* @date 2022/10/19 16:07
*/
//@WebFilter
//@Component
//@Order(2)
public class MyFilter2 implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化完成 2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//对请求进行预处理,如权限处理、IP过滤、敏感词过滤、跨域处理等等
logger.info("doFilter 2");
//预处理完成后判断是否允许放行,调用filterChain.doFilter()方法会回调过滤链里所有的过滤器,
// 所有过滤器处理完并调用此方法后请求会到达servlet,
// 如果任一过滤器未调用此方法都会导致请求无法到达servlet,即请求被拦截,shiro权限控制框架即是通过此接口实现
filterChain.doFilter(servletRequest,servletResponse);
// HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
// httpServletResponse.setCharacterEncoding("UTF-8");
// PrintWriter pw = httpServletResponse.getWriter();
//
// pw.write("请求未通过");
// pw.flush();
// pw.close();
}
@Override
public void destroy() {
}
}
4、分别访问/hello和/bye
其中/hello匹配到MyFilter3、MyFilter2、MyFilter1三个过滤器,/bye仅匹配到MyFilter2过滤器。
spring也提供了一些默认过滤器实现,比如字符编码过滤器、跨域过滤器等。
CharacterEncodingFilter继承自OncePerRequestFilter,OncePerRequestFilter继承自GenericFilterBean,GenericFilterBean实现了javax.servlet.Filter,CharacterEncodingFilter提供了3个属性可设置:
encoding:设置编码。
forceRequestEncoding:强制请求编码,若设置true,则强制使用此处设置的编码(其他地方设置被覆盖)。
forceResponseEncoding:强制响应编码,效果同上。
实现interceptor拦截器的方法:
自定义类实现org.springframework.web.servlet.HandlerInterceptor接口,该接口提供3个方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerInterceptor {
//根据匹配规则拦截action(springMVC里的Controller),在请求到达action之前调用,返回true则请求到达action,返回false则拦截请求
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
//在action处理完后返回前调用
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
//在action处理完并返回响应之后调用
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
1、自定义MyInterceptor1、MyInterceptor2实现org.springframework.web.servlet.HandlerInterceptor接口的三个方法
package com.example.demo.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* @author jiang
* @date 2022/10/21 15:38
*/
@Component
public class MyInterceptor1 implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
//请求到达action(controller)之前执行,返回true则放行,请求到达action,否则拦截
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("preHandle 1");
return true;
}
//action处理请求后return前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("postHandle 1");
}
//action处理完成return后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("afterCompletion 1");
}
}
package com.example.demo.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* @author jiang
* @date 2022/10/22 16:06
*/
@Component
public class MyInterceptor2 implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("preHandle 2");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("postHandle 2");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("afterCompletion 2");
}
}
2、自定义MyWebMvcConfigurer实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口,WebMvcConfigurer是spring容器提供的一种配置方式,采用Java配置类形式代替传统的XML文件对框架进行自定义设置,可以自定义配置类实现该接口的方法,然后自定义实现一些如HandleInterceptor、MessageConverter等注册到WebMvcConfigurer自定义实现类的相关注册器里实现对springMVC的自定义配置,先看看该接口提供了哪些方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet.config.annotation;
import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
public interface WebMvcConfigurer {
//配置路径匹配
default void configurePathMatch(PathMatchConfigurer configurer) {
}
//配置内容裁决的参数
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
//配置默认静态资源处理
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
//配置拦截器
default void addInterceptors(InterceptorRegistry registry) {
}
//配置静态资源处理
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
//跨域设置
default void addCorsMappings(CorsRegistry registry) {
}
//配置视图控制器
default void addViewControllers(ViewControllerRegistry registry) {
}
//配置视图解析器
default void configureViewResolvers(ViewResolverRegistry registry) {
}
//配置参数解析器
default void addArgumentResolvers(List resolvers) {
}
//配置返回值处理
default void addReturnValueHandlers(List handlers) {
}
//配置信息转换器
default void configureMessageConverters(List> converters) {
}
default void extendMessageConverters(List> converters) {
}
default void configureHandlerExceptionResolvers(List resolvers) {
}
default void extendHandlerExceptionResolvers(List resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
这里用到addInterceptors(InterceptorRegistry registry)方法,需要传入InterceptorRegistry实例:
自定义MyWebMvcConfigurer实现WebMvcConfigurer接口并实现addInterceptors()方法
package com.example.demo.config;
import com.example.demo.interceptor.MyInterceptor1;
import com.example.demo.interceptor.MyInterceptor2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author jiang
* @date 2022/10/22 13:56
*/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Autowired
private MyInterceptor1 myInterceptor1;
@Autowired
private MyInterceptor2 myInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注入2个拦截器,并设置优先级
InterceptorRegistration interceptorRegistration = registry.addInterceptor(myInterceptor1);
interceptorRegistration.addPathPatterns("/interceptor/*").order(2);
registry.addInterceptor(myInterceptor2).addPathPatterns("/interceptor/*").order(1);
}
}
3、自定义InterceptorController
package com.example.demo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author jiang
* @date 2022/10/22 16:39
*/
@RestController
@RequestMapping("/interceptor")
public class InterceptorController {
Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping("/hello")
public String hello(){
String str = "hello";
logger.info(str);
return str;
}
@RequestMapping("/bye")
public String bye(){
String str = "bye";
logger.info(str);
return str;
}
}
4、运行访问http://localhost:8080/interceptor/hello
可以看到,因为设置优先级所以MyInterceptor2#preHandle比MyInterceptor1#preHandle先执行,但是MyInterceptor2#postHandle和MyInterceptor2#afterCompletion在MyInterceptor1#postHandle和MyInterceptor1#afterCompletion之后执行,原因看调用源码DispatcherServlet#doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//获取处理器执行链,返回值是HandlerExecutionChain对象
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
//处理器执行链调用拦截器的preHandle()
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
//处理器执行链调用拦截器的postHandle()
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
再看HandlerExecutionChain#applyPreHandle()和HandlerExecutionChain#applyPostHandle()
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//遍历执行拦截器preHandle()
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//遍历执行拦截器postHandle(),但是与preHandle()遍历顺序相反
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
因为这俩方法遍历顺序相反,所以就出现调用preHandle和postHandle的顺序反过来,afterCompletion也是同理。