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,urlPatterns
和 value
的行为相同
@ServletComponentScan
会让 spring 找到 @WebFilter
,但正如 here 解释的那样,不允许使用注释 urlPatterns 字段。
感谢@pedrohreis 提供的信息。而不是使用@ServletComponentScan
你有什么建议?以上是关于Spring WebFilter 映射的主要内容,如果未能解决你的问题,请参考以下文章
@WebFilter(urlPatterns) 未正确映射 http 请求
Spring WebFlux添加WebFIlter以匹配特定路径