一篇文章看懂拦截器和过滤器的执行顺序和区别,全!

2023-12-31 15:28:26

上周学习了springboot集成websocket就使用了过滤器 (Filter),对指定的请求进行拦截设置响应头,所有借这个机会重新学习下总结拦截器和过滤器。

目录

一、过滤器(Filter)

1.1 基本概念

1.2?定义过滤器

1.3?过滤器的拦截路径配置

1.4?过滤器的执行流程

1.5?过滤器遇到的坑

二、拦截器(Interceptor)

2.1 基本概念

2.2?定义拦截器

2.3?注册拦截器

2.4?拦截器的拦截路径配置

?2.5?拦截器的执行流程

?2.6 拦截器遇到的坑

三、过滤器(Filter)和 拦截器(Interceptor)的区别

📝文章语:

一、过滤器(Filter)

1.1 基本概念

  • Filter 过滤器,是JavaWeb 三大组件(Servlet、Filter、Listener)之一
  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
  • 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

1.2?定义过滤器

第一种:@WebFilter+@ServletComponentScan(可以自定义拦截路径,无法控制多个过滤器顺序)

  • 1.定义Filter:定义一个类,实现 Filter 接口,并重写其所有方法
  • 2.配置Filter: Filter类上加 @WebFilter 注解,配置拦截资源的路径
  • 3.启动类上加 @ServletComponentScan 开启Servlet组件支持

测试接口:

    // http://127.0.0.1:8080/hello?name=lisi
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
        System.out.println("Hello " + name);
        return "Hello " + name;
    }

启动类加@ServletComponentScan

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class Demo1Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo1Application.class, args);
    }

}

Filter实现?:?

package com.example.demo.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author qujingye
 * @Classname Demofilter
 * @Description TODO
 * @Date 2023/12/26 21:16
 */
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {

    //初始化方法,Web服务器启动,创建Filter时调用,只调用一次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    //拦截到请求时,调用该方法,每次请求都会调用一次
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("拦截方法执行,拦截到了请求 ...");
        System.out.println("执行放行前逻辑 ...");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("执行放行后逻辑 ...");
    }

    //销毁方法,服务器关闭时调用,只调用一次
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

测试成功!!!

第二种:@Component+@Order() 这种无法自定义拦截路径,但是可以设置过滤器链的执行顺序,order挎号里面的值越小,越先拦截

package com.example.demo.filter;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author qujingye
 * @Classname DemoFilter2
 * @Description TODO
 * @Date 2023/12/26 21:42
 */
@Order(1)
@Component
public class DemoFilter2 extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("DemoFilter2拦截");
        filterChain.doFilter(request,response);
    }
}

?第三种:定义一个配置类,使用FilterRegistrationBean 可定义拦截器顺序和拦截路径

定义三个过滤器:

package com.example.demo.filter;
import javax.servlet.*;
import java.io.IOException;

/**
 * @author qujingye
 * @Classname DemoFilter1
 * @Description TODO
 * @Date 2023/12/26 21:42
 */

public class DemoFilter1 implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("DemoFilter1拦截");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
package com.example.demo.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author qujingye
 * @Classname DemoFilter2
 * @Description TODO
 * @Date 2023/12/26 21:42
 */
public class DemoFilter2 implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("DemoFilter2拦截");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
package com.example.demo.filter;
import javax.servlet.*;
import java.io.IOException;

/**
 * @author qujingye
 * @Classname DemoFilter3
 * @Description TODO
 * @Date 2023/12/26 21:42
 */
public class DemoFilter3 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("DemoFilter3拦截");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

?过滤器配置类:

package com.example.demo.filter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author qujingye
 * @Classname WebFilterConfig
 * @Description TODO
 * @Date 2023/12/26 22:06
 */
@Configuration
public class WebFilterConfig {
    @Bean
    public FilterRegistrationBean<DemoFilter1> DemoFilter1() {
        FilterRegistrationBean<DemoFilter1> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new DemoFilter1());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(2);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<DemoFilter2> DemoFilter2() {
        FilterRegistrationBean<DemoFilter2> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new DemoFilter2());
        registrationBean.addUrlPatterns("/*");  // 设置过滤器的URL模式
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<DemoFilter3> DemoFilter3() {
        FilterRegistrationBean<DemoFilter3> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new DemoFilter3());
        registrationBean.addUrlPatterns("/*");  // 设置过滤器的URL模式
        registrationBean.setOrder(3);
        return registrationBean;
    }

}

?测试结果成功!!!

把第三个过滤器的拦截路径调整下,看配置拦截路径是否失效? 改成只拦截/aaa 的请求

@Bean
    public FilterRegistrationBean<DemoFilter3> DemoFilter3() {
        FilterRegistrationBean<DemoFilter3> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new DemoFilter3());
        registrationBean.addUrlPatterns("/aaa");  // 设置过滤器的URL模式
        registrationBean.setOrder(3);
        return registrationBean;
    }

?请求的的路径:

测试成功!!! 所以 FilterRegistrationBean 即可定义拦截顺序 也可以定义拦截路径

1.3?过滤器的拦截路径配置


1.4?过滤器的执行流程


1.5?过滤器遇到的坑

1、使用@WebFilter,启动类不加@ServletComponentScan,@WebFilter描述的过滤器将扫描不到,对应的过滤器也无法注入及生效

2、请不要在过滤器实现类上同时加@WebFilter和@Component并且还在启动类上加@ServletComponentScan,这会导致过滤器拦截两次!!!

二、拦截器(Interceptor)

2.1 基本概念

  • 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行
  • 作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

2.2?定义拦截器

  • 定义拦截器,实现Handlerlnterceptor接口,并重写其所有方法。
package com.example.demo.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;

/**
 * @author qujingye
 * @Classname demoInterceptor
 * @Description TODO
 * @Date 2023/12/26 22:44
 */
@Component
public class DemoInterceptor implements HandlerInterceptor {

    //目标资源方法执行前执行,放回true: 放行,返回false: 不放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("目标资源方法执行前执行 == preHandle");
        return true;
    }

    //目标资源方法执行后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("目标资源方法执行后执行 == postHandle");
    }

    //视图渲染完毕后执行,最后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("视图渲染完毕后执行最后执行 == afterCompletion");
    }
}

2.3?注册拦截器

package com.example.demo.interceptor;

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.WebMvcConfigurer;

/**
 * @author qujingye
 * @Classname Webconfig
 * @Description TODO
 * @Date 2023/12/26 22:51
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private DemoInterceptor demoInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(demoInterceptor).addPathPatterns("/**");
    }
}

2.4?拦截器的拦截路径配置


2.5?拦截器的执行流程


2.6 拦截器遇到的坑

我看到有部分文章在注册拦截器的时候是这样的

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

这种new的方式注入,要注意MyInterceptor类里面,如果有用spring注入的属性将无法注入,属性将为null。

三、过滤器(Filter)和 拦截器(Interceptor)的区别

  • 接口规范不同: 过滤器需要实现Fiter接口,而拦截器需要实现Handlerlnterceptor接口。
  • 拦截范围不同:过滤器Filter会拦截所有的资源,而interceptor只会拦截Spring环境中的资源。
  • 拦截顺序不同:先拦截的是过滤器Filter然后是拦截器interceptor。

📝结束语:

总结不易😄觉得有用的话,还请各位大佬动动发财的小手
给小瞿扣个三连:?? 点赞??收藏 ?? 关注
这个对我真的非常重要,拜托啦!
本人水平有限,如有纰漏,欢迎各位大佬评论指正!💞
?

文章来源:https://blog.csdn.net/QJY1437758743/article/details/135219281
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。