Springboot 中 Filter 的使用

要使用Filter,首先我们应该了解过滤器与拦截器的区别

区别如下:

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

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

3 、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

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

5 、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

在 Spring Boot中使用Filter有两种方法。

在 Spring boot中使用Filter积累了一下的经验,首先,业务场景是,客户采用yml文件上传到系统,系统根据上传到的yml文件生成动态接口,以后用户使用动态接口进行业务操作。

这个业务的思路是:用户请求动态接口时,需要给他过滤到,不管是拦截到还是过滤到,不能让他到servlet的层面,让他报404,在拦截到之后进行业务的处理,然后直接返回。

最终选用了Filter,因为拦截器根据网上的demo进行配置后,并不能拦截到请求(这个在后文中会讲到),其实由于项目赶的比较紧,没有太多时间进行思考,其实针对于上面拦截器和过滤器的比较来说,使用拦截器会更好,因为由于业务需要,后面的版本可能需要拦截到action的上下文并访问到上下文的对象,而拦截器是做不到的。


下面是我在使用Filter的过程中踩过的坑:

由于Springboot的一大优点就是使用注解来生命很方便。于是就有了以下的一个方式来进行声明:

@Slf4j
@WebFilter(filterName = "urlFilter",urlPatterns = "/api/cds/common/*")
public class URLFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        String url = request.getRequestURI();
        log.info("the url of request is {}",url);
        //根绝url拿到API接口的配置 拿到 ApiInfoDTO
        //业务处理。。。
    }

    @Override
    public void destroy() {

    }
}

上面的主要的步骤就是实现了Filter接口,实现三个主要的方法,最主要的就是添加了 @WebFilter(filterName = "urlFilter",urlPatterns = "/api/cds/common/*")

以下是启动类的代码:

@SpringBootApplication
@ServletComponentScan
public class IscCdsServiceBootstrap {
    public static void main(String[] args) {
        IsysCoreSpringApplication.run(IscCdsServiceBootstrap.class, args);
    }
}

参照网上的说法是,加上@ServletComponentScan后,Spring容器就会创建Filter的实例,但是在调试过程中并没有创建自定义的Filter的bean,又有网上说,需要在自定义的Filter类上加上@Component或者是@Configuration注解,加上后,能够创建相关的bean对象,但是@WebFilter注解就失效了,路径匹配也就失效了,所有的请求路径都会被过滤,这肯定是不能够符合我的要求的。

这主要是因为加上了 @Component或者@Configuration之后,Spring在创建Filter这个bean的时候,就不会再走@WebFilter了,他就默认过滤全部的路径了。

由于时间比较急,所以就没来得急去深究,我就采用了另一种方式,采用配置类的形式进行创建的:

@Slf4j
public class URLFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        String url = request.getRequestURI();
        log.info("the url of request is {}",url);
        //根绝url拿到API接口的配置 拿到 ApiInfoDTO
        ApiInfoDTO apiInfoDTO = commonService.getApiInfo(url);
        //业务处理。。。
    }

    @Override
    public void destroy() {

    }
package com.isyscore.bigdatagroup.isccdsservice.config;

import com.isyscore.bigdatagroup.isccdsservice.filter.URLFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean authFilterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setName("urlFilter");
        registrationBean.setFilter(urlFilter());
        registrationBean.setOrder(1);
        List<String> urlList = new ArrayList<String>();
        //设置拦截路径
        urlList.add("/api/cds/common/*");
        registrationBean.setUrlPatterns(urlList);
        return registrationBean;
    }

    @Bean
    public URLFilter urlFilter(){
        return new URLFilter();
    }
}

这样的话就能够根据自定义的路径规则进行过滤了。


而对于拦截器来说,也会出现上述这种问题,根绝拦截器的问题来说,这可能是Spring的版本问题:

很多网上都采用以下的方法进行配置拦截器,你会发现按照上面的方式进行配置后,并不能够实现拦截,根本就没有走拦截器:

public class InterceptorDemo extends HandlerInterceptorAdapter {


    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        StringBuffer requestURL = httpServletRequest.getRequestURL();
        System.out.println("前置拦截器1 preHandle: 请求的uri为:"+requestURL.toString());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器1 postHandle: ");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("拦截器1 afterCompletion: ");
    }
}

然后注册自定义的拦截器:

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport{

	 /**
     * 注册自定义拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        
       	registry.addInterceptor(new InterceptorDemo2()).addPathPatterns("/**");
        registry.addInterceptor(new InterceptorDemo()).addPathPatterns("/**");
    }
 }

配置好后,你会发现并不能欧拦截到任何路径,也就是说,拦截器不起作用。这是因为 WebMvcConfigurationSupport 这个类,再行版本的Spring中就已经启用了。

解决办法是:

  1. 把WebMvcConfigurationSupport改为WebMvcConfigurer这个接口
  2. 把HandlerInterceptorAdapter改为HandlerInterceptor这个类就好了。

针对于Filter不起作用的问题,也很可能是因为版本问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值