在Spring Boot中,用于Web应用程序的Filter
类是否有任何注释?也许是@Filter
?
我想在我的项目中添加自定义过滤器。
Spring Boot参考指南提到了FilterRegistrationBean
,但我不确定如何使用它。
在Spring Boot中,用于Web应用程序的Filter
类是否有任何注释?也许是@Filter
?
我想在我的项目中添加自定义过滤器。
Spring Boot参考指南提到了FilterRegistrationBean
,但我不确定如何使用它。
FilterRegistrationBean
。例如,等价于web.xml的内容:<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>com.somecompany.SomeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<url-pattern>/url/*</url-pattern>
<init-param>
<param-name>paramName</param-name>
<param-value>paramValue</param-value>
</init-param>
</filter-mapping>
这将是您的@Configuration
文件中的两个bean:
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(someFilter());
registration.addUrlPatterns("/url/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("someFilter");
registration.setOrder(1);
return registration;
}
public Filter someFilter() {
return new SomeFilter();
}
以上内容已使用Spring Boot 1.2.3进行测试。
@Bean
注释在 someFilter()
上。 - Pavel VlasovFilter
在哪个软件包中?我看到有超过 24 个可能的匹配项。也许可以包括一个导入语句片段。 - dlamblin以下是在Spring Boot MVC应用程序中包含自定义过滤器的一种方法示例。确保在组件扫描中包含该包:
package com.dearheart.gtsc.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
public class XClacksOverhead implements Filter {
public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}
MetricsFilter
,但这个bean将被同名的Spring执行器bean掩盖。我已经吃过这方面的亏了... - kinbikoorg.springframework.web.filter.GenericFilterBean
? - Jakub Holý有三种方法可以添加过滤器:
@Component
来注解您的过滤器。 @Configuration
中注册Filter
类型的@Bean
。@Configuration
中注册FilterRegistrationBean
类型的@Bean
。如果您希望过滤器应用于所有请求而不需要自定义,请使用#1或#2。否则,请使用#3。对于#1,只要将过滤器类放在与您的SpringApplication
类相同或子包中,就不需要指定组件扫描即可工作。对于#3,仅当您希望Spring管理您的过滤器类(例如自动连接依赖项)时,才需要与#2一起使用。对于我所创建的不需要任何依赖项自动连接/注入的过滤器,直接实例化即可。
虽然组合#2和#3是有效的,但我很惊讶它不会导致两个过滤器重复应用。我猜测Spring在调用相同的方法创建这两个bean时将它们合并为一个。如果您想仅使用#3进行依赖注入,您可以使用AutowireCapableBeanFactory
。以下是一个示例:
private @Autowired AutowireCapableBeanFactory beanFactory;
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter myFilter = new MyFilter();
beanFactory.autowireBean(myFilter);
registration.setFilter(myFilter);
registration.addUrlPatterns("/myfilterpath/*");
return registration;
}
FilterRegistrationBean
时自动装配您的Filter
。 - sbk没有特别的注解来表示一个Servlet过滤器。您只需声明类型为Filter
(或FilterRegistrationBean
)的@Bean
。一个例子(向所有响应添加自定义标题)在Boot自己的EndpointWebMvcAutoConfiguration中;
如果您只声明了一个Filter
,它将应用于所有请求。如果您还添加了一个FilterRegistrationBean
,则可以进一步指定要应用的单个servlet和URL模式。
注意:
从Spring Boot 1.4开始,FilterRegistrationBean
未被弃用,仅将软件包从org.springframework.boot.context.embedded.FilterRegistrationBean
移动到org.springframework.boot.web.servlet.FilterRegistrationBean
更新:2022-05-29:
在Spring Boot 1.5.8.RELEASE中有两种简单的方法可以实现此操作,无需使用XML。
第一种方法:
如果您没有任何特定的URL模式,您可以像这样使用@Component(完整代码和详细信息在此处https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/3_spring-boot-filter,请查看README.txt开始):
@Component
public class ExampleFilter implements Filter {
...
}
第二种方法:
如果你想使用URL模式,你可以像这样使用@WebFilter(完整的代码和详细信息在这里:https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/4_spring-boot-filter-urlpattern ,查看README.txt开始):
@WebFilter(urlPatterns = "/api/count")
public class ExampleFilter implements Filter {
...
}
但你还需要在 @SpringBootApplication 类中添加 @ServletComponentScan 注解:
@ServletComponentScan
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
...
}
请注意,@Component是Spring的注解,但@WebFilter不是。@WebFilter是Servlet 3的注解。
无论哪种方式,您只需要在pom.xml中添加基本的Spring Boot依赖项(不需要显式添加Tomcat嵌入式Jasper)。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<groupId>com.surasint.example</groupId>
<artifactId>spring-boot-04</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
警告:如果在Spring Boot中Controller返回到JSP文件,第一种方式会导致请求通过过滤器两次。
而第二种方式只会让请求通过过滤器一次。
我更喜欢第二种方式,因为它更类似于Servlet规范中的默认行为。
这是我的自定义过滤器类的示例:
package com.dawson.controller.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class DawsonApiFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if (req.getHeader("x-dawson-nonce") == null || req.getHeader("x-dawson-signature") == null) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json");
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Required headers not specified in the request");
return;
}
chain.doFilter(request, response);
}
}
我通过将它添加到 Configuration 类中来将其添加到 Spring Boot 配置中,代码如下:
package com.dawson.configuration;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.dawson.controller.filter.DawsonApiFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@SpringBootApplication
public class ApplicationConfiguration {
@Bean
public FilterRegistrationBean dawsonApiFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DawsonApiFilter());
// In case you want the filter to apply to specific URL patterns only
registration.addUrlPatterns("/dawson/*");
return registration;
}
}
从Spring文档中,
嵌入式servlet容器 - 向应用程序添加Servlet、Filter或Listener
要添加Servlet、Filter或Servlet *Listener,请为其提供@Bean定义。
例如:
@Bean
public Filter compressFilter() {
CompressingFilter compressFilter = new CompressingFilter();
return compressFilter;
}
将下面的内容翻译为中文:
将此@Bean
配置添加到您的@Configuration
类中,过滤器将在启动时注册。
您还可以使用类路径扫描添加Servlet、Filter和Listener,
@WebServlet、@WebFilter和@WebListener注解的类可以通过在@Configuration类上注释@ServletComponentScan并指定要注册的组件所在的package(s),自动注册到嵌入式servlet容器中。 默认情况下,@ServletComponentScan将从注释类的包扫描。
通过在@Configuration类上注释@ServletComponentScan,并指定包含要注册的组件的包(s),自动将带有@WebServlet、@WebFilter和@WebListener注解的类注册到嵌入式servlet容器中。默认情况下,@ServletComponentScan将从注释类的包扫描。
我们大约有四个不同的选项来 使用Spring注册过滤器。
首先,我们可以创建一个实现Filter或扩展HttpFilter的Spring bean:
@Component
public class MyFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Implementation details...
chain.doFilter(request, response);
}
}
@Component
public class MyFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
//Implementation details...
chain.doFilter(currentRequest, servletResponse);
}
}
或者我们可以使用FilterRegistrationBean类:
@Configuration
public class FilterConfiguration {
private final MyFilter myFilter;
@Autowired
public FilterConfiguration(MyFilter myFilter) {
this.myFilter = myFilter;
}
@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistration() {
FilterRegistrationBean<DateLoggingFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(myFilter);
filterRegistrationBean.setUrlPatterns(Collections.singletonList("/*"));
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST);
filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
return filterRegistrationBean;
}
}
最后,我们可以使用@WebFilter注解和@ServletComponentScan:
@WebFilter(urlPatterns = "/*", dispatcherTypes = {DispatcherType.REQUEST})
public class MyFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Implementation details...
chain.doFilter(request, response);
}
}
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired FilterDependency filterDependency;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(
new MyFilter(filterDependency),
UsernamePasswordAuthenticationFilter.class);
}
}
过滤器类
class MyFilter extends OncePerRequestFilter {
private final FilterDependency filterDependency;
public MyFilter(FilterDependency filterDependency) {
this.filterDependency = filterDependency;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
// Filter
filterChain.doFilter(request, response);
}
}
@WebFilter(urlPatterns = {"/*" })
public class AuthenticationFilter implements Filter{
private static Logger logger = Logger.getLogger(AuthenticationFilter.class);
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("checking client id in filter");
HttpServletRequest request = (HttpServletRequest) arg0;
String clientId = request.getHeader("clientId");
if (StringUtils.isNotEmpty(clientId)) {
chain.doFilter(request, response);
} else {
logger.error("client id missing.");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}