【问题标题】:Spring WebFilter MappingSpring WebFilter 映射
【发布时间】: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/* 模式的请求,但过滤对任何资源的请求。

如何映射我的过滤器?

谢谢。

【问题讨论】:

    标签: java spring spring-mvc servlet-filters


    【解决方案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 documentationurlPatternsvalue 的行为相同
      • @ServletComponentScan 会让 spring 找到 @WebFilter,但正如 here 解释的那样,不允许使用注释 urlPatterns 字段。
      • 感谢@pedrohreis 提供的信息。而不是使用@ServletComponentScan 你有什么建议?
      猜你喜欢
      • 2018-09-12
      • 2012-08-14
      • 2014-09-24
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 2013-05-30
      • 2016-05-17
      • 2016-01-02
      相关资源
      最近更新 更多