Spring WebFilter 映射

Posted

技术标签:

【中文标题】Spring WebFilter 映射【英文标题】:Spring WebFilter Mapping 【发布时间】:2016-11-22 18:19:54 【问题描述】:

我正在尝试在我的 spring 应用程序中添加一个 WebFilter。但是,我没有使用 .xml 文件(甚至没有 web.xml,因为我的应用程序不需要它)。

所以,我添加到扩展 AbstractAnnotationConfigDispatcherServletInitializer 的类中:

@Override
protected Filter[] getServletFilters() 
    return new Filter[]new RequestFilter();

还有,我的 RequestFilter.java:

@WebFilter("/test/*")
public class RequestFilter implements Filter 

@Override
public void init(FilterConfig filterConfig) throws ServletException  

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException  

@Override
public void destroy()  

我希望只过滤匹配/test/* 模式的请求,但过滤对任何资源的请求。

如何映射我的过滤器?

谢谢。

【问题讨论】:

【参考方案1】:

@WebFilter - 不是 Spring 注释。春天忽略它。方法 getServletFilters 返回一个过滤器数组,而不将它们映射到 URL。所以他们触发了每个请求。如果不想在 web.xml 中写 url-mappings,可以使用HandlerInterceptor 代替Filter。它们可以在DispatcherServletInitializer 中以编程方式映射:

public class SomeInterceptor extends HandlerInterceptorAdapter 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception 
        // ...
        return true;
    


@Configuration
@ComponentScan("com.example")
@EnableWebMvc  
public class AppConfig extends WebMvcConfigurerAdapter  
    @Override
    public void addInterceptors(InterceptorRegistry registry) 
        registry
          .addInterceptor(new SomeInterceptor())
          .addPathPatterns("/test/*");
    


public class WebAppInitializer implements WebApplicationInitializer 
    public void onStartup(ServletContext servletContext) throws ServletException   
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();  
        ctx.register(AppConfig.class);  
        ctx.setServletContext(servletContext);    
        Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));  
        dynamic.addMapping("/");  
        dynamic.setLoadOnStartup(1);  
     

或者你可以定义你自己的 WebFilter 注解!

首先,您需要用于匹配 URL 模式的实用程序类:

public class GlobMatcher 
    public static boolean match(String pattern, String text) 
        String rest = null;
        int pos = pattern.indexOf('*');
        if (pos != -1) 
            rest = pattern.substring(pos + 1);
            pattern = pattern.substring(0, pos);
        

        if (pattern.length() > text.length())
            return false;

        for (int i = 0; i < pattern.length(); i++)
            if (pattern.charAt(i) != '?' 
                    && !pattern.substring(i, i + 1).equalsIgnoreCase(text.substring(i, i + 1)))
                return false;

        if (rest == null) 
            return pattern.length() == text.length();
         else 
            for (int i = pattern.length(); i <= text.length(); i++) 
                if (match(rest, text.substring(i)))
                    return true;
            
            return false;
        
    

注解本身:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface WebFilter 
    String[] urlPatterns();

URL 模式匹配的直通功能:

@Aspect
public class WebFilterMatcher 
    @Pointcut("within(@com.example.WebFilter *)")
    public void beanAnnotatedWithWebFilter() 

    @Pointcut("execution(boolean com.example..preHandle(..))")
    public void preHandleMethod() 

    @Pointcut("preHandleMethod() && beanAnnotatedWithWebFilter()")
    public void preHandleMethodInsideAClassMarkedWithWebFilter() 

    @Around("preHandleMethodInsideAClassMarkedWithWebFilter()")
    public Object beforeFilter(ProceedingJoinPoint joinPoint) throws Throwable 
        Object[] args = joinPoint.getArgs();
        if(args.length > 0) 
            HttpServletRequest request = (HttpServletRequest) args[0];
            Class target = joinPoint.getTarget().getClass();
            if (target.isAnnotationPresent(WebFilter.class)) 
                String[] patterns = ((WebFilter) target.getAnnotation(WebFilter.class)).urlPatterns();
                for (String pattern : patterns) 
                    if (GlobMatcher.match(pattern, request.getRequestURI())) 
                        return joinPoint.proceed();
                    
                
            
        
        return true;
    

拦截器:

@WebFilter(urlPatterns = "/test/*")
public class SomeInterceptor extends HandlerInterceptorAdapter  
    @Override 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception  
        // ...
        return true; 
    

还有一点上下文配置的改变:

<beans> <!-- Namespaces are omitted for brevity -->
  <aop:aspectj-autoproxy />

  <bean id="webFilterMatcher" class="com.example.WebFilterMatcher" />

  <mvc:interceptors>
    <bean class="com.example.SomeInterceptor" />
  </mvc:interceptors>
</beans>

【讨论】:

谢谢,谢尔盖。我完全忘记了这个线程。但最后,我使用了拦截器。只是为了进行注册,如果您使用的是 Spring Security,则过滤器也可能包含在 HttpSecurity 对象中的 SecurityFilterChain 中。【参考方案2】:

您可以将@Component 注解添加到您的过滤器实现中,或者如果使用 Spring Boot,则将 @ServletComponentScan 添加到您的主类中。

【讨论】:

这不允许使用注释 urlPatterns 字段配置过滤的 URL。【参考方案3】:

另一种选择是使用 FilterRegistrationBean 注册自定义过滤器类,而不是将过滤器本身添加为 bean。示例:

@Bean
public FilterRegistrationBean<RequestResponseLoggingFilter> loggingFilter()
    FilterRegistrationBean<RequestResponseLoggingFilter> registrationBean 
      = new FilterRegistrationBean<>();

    registrationBean.setFilter(new RequestResponseLoggingFilter());
    registrationBean.addUrlPatterns("/users/*");            
    return registrationBean;    

取自:https://www.baeldung.com/spring-boot-add-filter

【讨论】:

【参考方案4】:
@WebFilter("/test/*")
public class RequestFilter implements Filter 

应该是

@WebFilter(urlPatterns = "/test/*")
public class RequestFilter implements Filter 

你的 Spring Boot 应用程序类应该如下所示

@ServletComponentScan
@SpringBootApplication
public class Application 

【讨论】:

根据 java ee documentation,urlPatternsvalue 的行为相同 @ServletComponentScan 会让 spring 找到 @WebFilter,但正如 here 解释的那样,不允许使用注释 urlPatterns 字段。 感谢@pedrohreis 提供的信息。而不是使用@ServletComponentScan 你有什么建议?

以上是关于Spring WebFilter 映射的主要内容,如果未能解决你的问题,请参考以下文章

@WebFilter(urlPatterns) 未正确映射 http 请求

JavaWeb统一解决中文乱码问题

spring boot webfilter 顺序

Spring WebFlux添加WebFIlter以匹配特定路径

更改 Spring Security WebFilter 的顺序

将 WebFilter Spring WebFlux 添加到路径