SpringMVC--过滤器/拦截器
发布日期:2021-05-10 13:43:48 浏览次数:16 分类:精选文章

本文共 29095 字,大约阅读时间需要 96 分钟。

其他网址

过滤器/拦截器/AOP

其他网址

过滤器:《JSP&Servlet学习笔记》=> 5.3过滤器

拦截器:《深入浅出Spring Boot2.x》

简介

过滤器:Filter。拦截器:Interceptor  。

在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情,interceptor 都能够轻松的实现。

AOP:可以自定义切入的点,有方法的参数,但拿不到http请求,可以通过RequestContextHolder等方式获得。

     AOP用法见:

调用顺序

过滤前=> 拦截前=> AOP=> Controller=> AOP=> 拦截后=> 过滤后

不同点

过滤器 拦截器
使用场景 对请求/响应进行修改、判断等。一般用于过滤参数、登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换。 在service或者一个方法前/后调用一个方法,或者在方法后调用一个方法。
能力

可以拿到原始的http请求与响应,拿不到请求的控制器和请求控制器中的方法的信息。

可以修改请求、响应、参数:比如:修改字符编码、删除低俗文字、删除危险字符、修改参数

可以拿到你请求的控制器和方法,却拿不到请求与响应。
顺序 可指定顺序。 可指定顺序。
实现方式 回调函数 AOP
使用范围 只能用于Web 可用于Web、Application、Swing
作用范围 所有请求。 只能是controller请求。静态资源无法控制。
使用位置 controller前后、dispaterServlet前后 controller前后
规范定义

Servlet 规范定义,Servlet 容器支持。

Filter 接口定义在 javax.servlet 包

Spring容器内,Spring框架支持。

HandlerInterceptor 接口 定义在org.springframework.web.servlet 包

灵活性/粒度

灵活性差(粒度大)。

不能够使用 Spring 容器资源

灵活性好(粒度小)。

能使用Spring里的任何资源、对象,例如 Service对象、数据源、事务管理等,通过IoC注入到拦截器即可。

打断链路 打断方法:处理请求和响应对象来引发中断,需要额外的动作,比如将用户重定向到错误页面。 打断方法:preHandle方法内返回 false
执行次数

一个controller周期只调用一次:一个过滤器实例只能在容器初始化时调用一次。

一个controller周期可调用多次

公共代码

package com.example.controller;import com.example.entity.User;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/hello")public class HelloController {    @RequestMapping("/test1")    public User test1(User user) {        System.out.println("HelloController.test1");        return user;    }}

过滤器

其他网址

简介 

说明

Filter可以有多个。一个filter执行完之后会执行另外一个。

JavaDoc对过滤器使用场景的描述

Examples that have been identified for this design are<br>

(1) Authentication Filters,              //用户访问权限过滤
(2) Logging and Auditing Filters, //日志过滤,可以记录特殊用户的特殊请求的记录等
(3) Image conversion Filters
(4) Data compression Filters <br>
(5) Encryption Filters <br>
(6) Tokenizing Filters <br>          //过滤Token
(7) Filters that trigger resource access events <br>
(8) XSL/T filters <br>
(9) Mime-type chain Filter <br>

实例(单过滤器)

两种方式注册filter(两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter ):

1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter。缺点:无法指定过滤器顺序

注册方式1:FilterRegistrationBean

定义Filter 

package com.example.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class MyFilter implements Filter {    @Override    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {        System.out.println("MyFilter.init");        System.out.println("  过滤器名:" + filterConfig.getFilterName());    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        // do something 处理request 或response        System.out.println("MyFilter.doFilter");        if (servletRequest instanceof HttpServletRequest) {            System.out.println("  URL:" + ((HttpServletRequest)servletRequest).getRequestURL());        }        // 调用filter链中的下一个filter        filterChain.doFilter(servletRequest,servletResponse);    }    @Override    public void destroy() {        System.out.println("MyFilter.destroy");    }}

注册自定义Filter 

package com.example.filter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FilterConfig {    @Bean    public FilterRegistrationBean registrationBean() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());        filterRegistrationBean.addUrlPatterns("/*");        return filterRegistrationBean;    }}

方式2:@WebFilter

package com.example.filter;import org.springframework.stereotype.Component;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@Component// 定义filterName 和过滤的url@WebFilter(filterName = "myFilter" ,urlPatterns = "/*")public class MyFilter implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("MyFilter.init");        System.out.println("  过滤器名:" + filterConfig.getFilterName());    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        // do something 处理request 或response        System.out.println("MyFilter.doFilter");        if (servletRequest instanceof HttpServletRequest) {            System.out.println("  URL:" + ((HttpServletRequest)servletRequest).getRequestURL());        }        // 调用filter链中的下一个filter        filterChain.doFilter(servletRequest,servletResponse);    }    @Override    public void destroy() {        System.out.println("MyFilter.destroy");    }}

测试结果

启动SpringBoot

2020-09-04 23:25:27.216  INFO 16948 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext2020-09-04 23:25:27.216  INFO 16948 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 781 msMyFilter.init  过滤器名:myFilter2020-09-04 23:25:27.361  INFO 16948 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'2020-09-04 23:25:27.493  INFO 16948 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''2020-09-04 23:25:27.501  INFO 16948 --- [           main] com.example.DemoApplication              : Started DemoApplication in 1.44 seconds (JVM running for 2.276)2020-09-04 23:25:40.252  INFO 16948 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'2020-09-04 23:25:40.253  INFO 16948 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'2020-09-04 23:25:40.257  INFO 16948 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 4 ms

postman访问:

后端结果:

MyFilter.doFilter  URL:http://localhost:8080/hello/test1HelloController.test1

postman结果

{    "id": null,    "name": "Tony",    "age": null}

 关闭SpringBoot

Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket'MyFilter.destroy2020-09-04 23:26:00.810  INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

实例(多过滤器)

过滤器1

package com.example.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class MyFilter1 implements Filter {    @Override    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {        System.out.println("MyFilter1.init");        System.out.println("  过滤器名:" + filterConfig.getFilterName());    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,             FilterChain filterChain) throws IOException, ServletException {        // do something 处理request 或response        System.out.println("MyFilter1.doFilter");        if (servletRequest instanceof HttpServletRequest) {            System.out.println("  URL:" + ((HttpServletRequest)servletRequest).getRequestURL());        }        // 调用filter链中的下一个filter        filterChain.doFilter(servletRequest,servletResponse);    }    @Override    public void destroy() {        System.out.println("MyFilter1.destroy");    }}

过滤器2

package com.example.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class MyFilter2 implements Filter {    @Override    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {        System.out.println("MyFilter2.init");        System.out.println("  过滤器名:" + filterConfig.getFilterName());    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,                          FilterChain filterChain) throws IOException, ServletException {        // do something 处理request 或response        System.out.println("MyFilter2.doFilter");        if (servletRequest instanceof HttpServletRequest) {            System.out.println("  URL:" + ((HttpServletRequest)servletRequest).getRequestURL());        }        // 调用filter链中的下一个filter        filterChain.doFilter(servletRequest,servletResponse);    }    @Override    public void destroy() {        System.out.println("MyFilter2.destroy");    }}

配置类

package com.example.filter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FilterConfig {    @Bean    public FilterRegistrationBean registrationBean1() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter1());        filterRegistrationBean.addUrlPatterns("/*");//        filterRegistrationBean.setName("xxx");  //可设置过滤器名字        //过滤器执行顺序。(决定doFilter顺序,不决定init和destroy顺序)        filterRegistrationBean.setOrder(1);        return filterRegistrationBean;    }    @Bean    public FilterRegistrationBean registrationBean2() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter2());        filterRegistrationBean.addUrlPatterns("/*");//        filterRegistrationBean.setName("xxx");  //可设置过滤器名字        //过滤器执行顺序(决定doFilter顺序,不决定init和destroy顺序)        filterRegistrationBean.setOrder(2);        return filterRegistrationBean;    }}

执行结果

启动SpringBoot

MyFilter2.init  过滤器名:myFilter2MyFilter1.init  过滤器名:myFilter1

postman访问:

后端结果

MyFilter1.doFilter  URL:http://localhost:8080/hello/test1MyFilter2.doFilter  URL:http://localhost:8080/hello/test1HelloController.test1

postman结果

{    "id": null,    "name": "Tony",    "age": null}

关闭SpringBoot 

Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket'MyFilter2.destroyMyFilter1.destroy2020-09-04 23:26:00.810  INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

测试结果(配置类setOrder的值调换顺序)

配置类:

package com.example.filter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FilterConfig {    @Bean    public FilterRegistrationBean registrationBean1() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter1());        filterRegistrationBean.addUrlPatterns("/*");//        filterRegistrationBean.setName("xxx");  //可设置过滤器名字        //过滤器执行顺序。(决定doFilter顺序,不决定init和destroy顺序)        filterRegistrationBean.setOrder(2);        return filterRegistrationBean;    }    @Bean    public FilterRegistrationBean registrationBean2() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter2());        filterRegistrationBean.addUrlPatterns("/*");//        filterRegistrationBean.setName("xxx");  //可设置过滤器名字        //过滤器执行顺序(决定doFilter顺序,不决定init和destroy顺序)        filterRegistrationBean.setOrder(1);        return filterRegistrationBean;    }}

测试: 

启动SpringBoot

MyFilter2.init  过滤器名:myFilter2MyFilter1.init  过滤器名:myFilter1

postman访问

后端结果

MyFilter2.doFilter  URL:http://localhost:8080/hello/test1MyFilter1.doFilter  URL:http://localhost:8080/hello/test1HelloController.test1

postman结果

{    "id": null,    "name": "Tony",    "age": null}

关闭SpringBoot

Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket'MyFilter2.destroyMyFilter1.destroy2020-09-04 23:26:00.810  INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

拦截器

其他网址

简介 

使用场景

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等
  • 权限检查:如登录检测,进入处理器检测检测是否登录
  • 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如apache也可以自动记录);
  • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

Interceptor 的相关方法

Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,实现 HandlerInterceptor 接口需要实现下面三个方法:

  1. preHandle()           – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。
  2. postHandle()         – 在handler执行之后, 可以在返回之前对返回的结果进行修改
  3. afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等

注意事项

推荐写法

  • 实现WebMvcConfigurer接口是官方推荐的

不推荐写法

  • 实现WebMvcConfigurerAdapter:Spring5.0之后是废弃的。
  • 继承WebMvcConfigurationSupport:会导致yml的配置失效。原因:WebMvcAutoConfiguration有个条件注解:@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

实例(单拦截器拦截所有)

拦截器类

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor.preHandle");        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor.afterCompletion");    }}

配置类 

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new MyInterceptor());//        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/hello/test2");    }}

测试结果

postman访问

后端结果:

MyInterceptor.preHandleHelloController.test1MyInterceptor.postHandleMyInterceptor.afterCompletion

postman结果

{    "id": null,    "name": "Tony",    "age": null}

实例(单拦截器拦截特定URL)

拦截器类

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor.preHandle");        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor.afterCompletion");    }}

配置类 

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {//        registry.addInterceptor(new MyInterceptor());       registry.addInterceptor(new MyInterceptor()).addPathPatterns("/hello/test2");    }}

测试结果 

postman访问:

后端结果:

HelloController.test1

postman结果

{    "id": null,    "name": "Tony",    "age": null}

实例(单拦截器结合注解)

使用场景示例:在需要登录验证的Controller的方法上使用注解。当然,也可以直接通过HttpServletRequest获得URI来判断。

注解类

package com.example.interceptor;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 在需要登录验证的Controller的方法上使用此注解 */@Target({ElementType.METHOD})      // 可用在方法名上@Retention(RetentionPolicy.RUNTIME)// 运行时有效public @interface LoginRequired {	}

拦截器类

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.lang.reflect.Method;public class MyInterceptor3 implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor3.preHandle");        // 如果不是映射到方法直接通过        if (!(handler instanceof HandlerMethod)) {            return true;        }        // 方法注解级拦截器        HandlerMethod handlerMethod = (HandlerMethod) handler;        Method method = handlerMethod.getMethod();        // 判断接口是否需要登录。也可用method.isAnnotationPresent(LoginRequired.class)        LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);        // 有 @LoginRequired 注解,需要认证        if (methodAnnotation != null) {            // 取缓存,SESSION,权限判断等            System.out.println("   权限判断等");            return true;        }        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor3.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor3.afterCompletion");    }}

拦截器配置

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        //这个顺序会决定拦截器执行顺序        registry.addInterceptor(new MyInterceptor3());//        registry.addInterceptor(new MyInterceptor2());//        registry.addInterceptor(new MyInterceptor1());//        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/hello/test2");    }}

controller

package com.example.controller;import com.example.entity.User;import com.example.interceptor.LoginRequired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/hello")public class HelloController {    @LoginRequired    @RequestMapping("/test1")    public User test1(User user) {        System.out.println("HelloController.test1");        return user;    }}

测试结果

postman访问

后端结果

MyInterceptor3.preHandle   权限判断等HelloController.test1MyInterceptor3.postHandleMyInterceptor3.afterCompletion

postman结果

{    "id": null,    "name": "Tony",    "age": null}

实例(多个拦截器拦截所有)

拦截器1

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor1 implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor1.preHandle");        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor1.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor1.afterCompletion");    }}

拦截器2

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor2 implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor2.preHandle");        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor2.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor2.afterCompletion");    }}

配置类

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        //如果不写.order,则按照先后顺序        registry.addInterceptor(new MyInterceptor1()).order(0);        registry.addInterceptor(new MyInterceptor2()).order(1);    }}

测试结果

postman访问:

后端结果

MyInterceptor1.preHandleMyInterceptor2.preHandleHelloController.test1MyInterceptor2.postHandleMyInterceptor1.postHandleMyInterceptor2.afterCompletionMyInterceptor1.afterCompletion

postman结果

{    "id": null,    "name": "Tony",    "age": null}

配置类(颠倒顺序)

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        //如果不写.order,则按照先后顺序        registry.addInterceptor(new MyInterceptor2()).order(0);        registry.addInterceptor(new MyInterceptor1()).order(1);    }}

测试结果(颠倒顺序后)

postman访问:

后端结果

MyInterceptor2.preHandleMyInterceptor1.preHandleHelloController.test1MyInterceptor1.postHandleMyInterceptor2.postHandleMyInterceptor1.afterCompletionMyInterceptor2.afterCompletion

postman结果

{    "id": null,    "name": "Tony",    "age": null}

联合实例:过滤/拦截/@ControllerAdvice/AOP

实体类

package com.example.entity;import lombok.Data;@Datapublic class User {    private Integer id;    private String name;    private Integer age;}

控制器

package com.example.controller;import com.example.entity.User;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/hello")public class HelloController {    @RequestMapping("/test1")    public User test1(User user) {        System.out.println("HelloController.test1");        return user;    }}

过滤器

package com.example.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class MyFilter implements Filter {    @Override    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {        System.out.println("MyFilter.init");        System.out.println("  过滤器名:" + filterConfig.getFilterName());    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,                         FilterChain filterChain) throws IOException, ServletException {        // do something 处理request 或response        System.out.println("MyFilter.doFilter");        if (servletRequest instanceof HttpServletRequest) {            System.out.println("  URL:" + ((HttpServletRequest)servletRequest).getRequestURL());        }        // 调用filter链中的下一个filter        filterChain.doFilter(servletRequest,servletResponse);    }    @Override    public void destroy() {        System.out.println("MyFilter.destroy");    }}
package com.example.filter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FilterConfig {    @Bean    public FilterRegistrationBean registrationBean1() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());        filterRegistrationBean.addUrlPatterns("/*");//        filterRegistrationBean.setName("xxx");  //可设置过滤器名字        return filterRegistrationBean;    }}

 拦截器

package com.example.interceptor;import org.springframework.lang.Nullable;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        System.out.println("MyInterceptor.preHandle");        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response,                           Object handler, @Nullable ModelAndView modelAndView) throws Exception {        System.out.println("MyInterceptor.postHandle");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,                                Object handler, @Nullable Exception ex) throws Exception {        System.out.println("MyInterceptor.afterCompletion");    }}
package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new MyInterceptor());    }}

@ControllerAdvice

package com.example.advice;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ModelAttribute;@ControllerAdvicepublic class GlobalControllerAdvice {    @ModelAttribute    public void authenticationUser() {        System.out.println("GlobalControllerAdvice.authenticationUser");    }}

对@RequestMapping的AOP

package com.example.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Componentpublic class RequestMappingAspect {    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")    public void pointcut() {    }    @Around("pointcut()")    public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {        System.out.println("[RequestMappingAspect.around1]: around before");        Object object = joinPoint.proceed();        System.out.println("[RequestMappingAspect.around1]: around after");        return object;    }}

测试

启动SpringBoot

MyFilter.init  过滤器名:myFilter

postman访问:

后端结果

MyFilter.doFilter  URL:http://localhost:8080/hello/test1MyInterceptor.preHandleGlobalControllerAdvice.authenticationUser[RequestMappingAspect.around1]: around beforeHelloController.test1[RequestMappingAspect.around1]: around afterMyInterceptor.postHandleMyInterceptor.afterCompletion

 

postman结果

{    "id": null,    "name": "Tony",    "age": null}

关闭SpringBoot

Disconnected from the target VM, address: '127.0.0.1:61631', transport: 'socket'MyFilter.destroy2020-09-05 17:49:01.499  INFO 17144 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

 

上一篇:Spring AOP系列--AOP+注解 实例
下一篇:SpringMVC系列--Cookie

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月03日 11时40分28秒