过滤器和拦截器

filter依赖于servlet,而interceptor是spring中有封装的,依赖于springmvc

过滤器

过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter注解实现对特定URL拦截,看到Filter 接口中定义了三个方法。

  • init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。注意:这个方法必须执行成功,否则过滤器会不起作用。
  • doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。
  • destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次。
@Component
@WebFilter("/myservlet1")//过滤路径
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("Filter 前置");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter 处理中");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

        System.out.println("Filter 后置");
    }
}

优先级:可以使用@Order()注解,值越小级别越高越先执行。

● 如果为注解的话,是按照类全名称的字符串顺序决定作用顺序

● 如果web.xml,按照 filter-mapping注册顺序,从上往下

● web.xml配置高于注解方式

拦截器

拦截器: 本身会在请求进入Controller控制层前后做拦截处理.

常见使用场景:
  • 接口重复提交校验 放置用户重复提交相同数据.
  • 权限检查 当前用户是否登录,是否有权限访问数据.
  • 日志记录 记录请求信息,输出成日志文件.
  • 性能监控 慢日志.
使用实操

定义多个拦截器可以实现WebMvcConfigurer,重写添加拦截的方法

@Configuration
public class MVCConfig implements WebMvcConfigurer{

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         // registry.addInterceptor(new LoginInterceptor())
         //        .addPathPatterns("/**")  //所有请求都被拦截包括静态资源(如下实现静态资源放行)
         //        .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求

        registry.addInterceptor(new LoginInterceptor(stringRedisTemplate)).excludePathPatterns(
                "/shop/**",
                "/voucher/**",
                "/shop-type/**",
                "/upload/**",
                "/blog/hot",
                "/user/code",
                "/user/login"
        ).order(1);
        // token刷新的拦截器,拦截所有请求
        registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
    }
}

拦截器默认的执行顺序,就是它的注册顺序,也可以通过Order手动设置控制,值越小越先执行。

实现HandlerInterceptor,定义拦截器

拦截器加载的时间点在springcontext之前,所以需要使用构造器传入spring容器中的bean;或者将自定义的拦截器注入容器+在这个类下注入需要使用的依赖

public class RefreshTokenInterceptor implements HandlerInterceptor {

    //由于这个类是自定义的,非spring注解构建,所以不能使用spring依赖注入,
    //可以使用构造器注入,也可以在拦截器类加上注解@component等
    StringRedisTemplate stringRedisTemplate;

    public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

重写三个方法...
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("request before 拦截");
        return true;

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("post 拦截");

    }

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

StringRedisTemplate是容器spring-data-redis包下的类

多个拦截器执行顺序

除重写的preHandle方法是先定义先执行外,其它两个方法都是后定义先执行

过滤器与拦截器的区别

1> 拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2> 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。

而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。

3> 拦截器只能对action请求起作用(拦截器只会对Controller中请求或访问static目录下的资源请求起作用。),而过滤器则可以对几乎所有的请求起作用。

4> 拦截器可以访问action上下文、栈值里的对象,而过滤器不能访问。

5> 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。(注:这里的调用一次,是对于构造函数而言。而doFilter会对匹配的请求做持续的处理。)

6> 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,所以我们可以在拦截器里注入一个service,可以调用业务逻辑。

过滤器、拦截器和IOC容器执行顺序

在Spring Boot中,过滤器、拦截器和IOC容器的执行顺序如下:

  1. 过滤器(Filter): 过滤器是在Servlet容器中的第一层,当请求进入Servlet容器时,会首先经过过滤器。过滤器的主要作用是对请求进行预处理,如身份验证、字符编码等。
  2. IOC容器: Spring Boot的IOC容器负责管理和维护所有的Bean对象,将根据配置文件或注解创建和初始化Bean对象,并且自动进行依赖注入。IOC容器会在应用程序启动时创建,根据配置的执行顺序初始化Bean对象。
  3. 拦截器(Interceptor): 拦截器在处理请求的过程中,对请求和响应进行拦截和处理。拦截器会在IOC容器创建并初始化好的Bean对象中进行设置,并且可以在请求前后进行一些特定的处理逻辑。

在Spring中,Filter是在Servlet容器中定义的,它在请求进入Servlet容器后,但在进入Spring的IOC容器之前执行。Interceptor则是在Spring的MVC框架中定义的,它在请求进入Spring的IOC容器之后执行。

filter之前调用ioc容器的bean

如果需要在Filter中调用IOC容器中的bean来查询数据库,可以通过手动获取IOC容器的方式来实现。以下是一个简化的示例代码:

public class MyFilter implements Filter {
    private ApplicationContext context;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取ApplicationContext
        context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        // 在过滤器中调用IOC容器中的bean查询数据库
        MyService myService = context.getBean(MyService.class);
        myService.queryDatabase();

        // 继续执行过滤器链
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        // 清理资源
    }
}

在上述示例代码中,通过使用WebApplicationContextUtils类的getWebApplicationContext方法获取Root WebApplicationContext,然后通过getBean方法获取需要调用的bean对象。注意,在使用Filter中调用IOC容器的bean时,需要确保IOC容器已经初始化完毕。

需要注意的是,这种方式破坏了Filter与IOC容器的解耦,一般不推荐在Filter中直接调用IOC容器中的bean。更好的做法是将查询数据库的逻辑放到Service层,然后在Filter中调用Service层的方法,遵循单一职责原则,提高代码的可维护性和可测试性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值