要使用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中就已经启用了。
解决办法是:
- 把WebMvcConfigurationSupport改为WebMvcConfigurer这个接口
- 把HandlerInterceptorAdapter改为HandlerInterceptor这个类就好了。
针对于Filter不起作用的问题,也很可能是因为版本问题。