Basically, there are 3 steps to create a filter: - Write a Java class that implements the Filter interface and override filter's life cycle methods. - Specify initialization parameters for the filter (optional). - Specify filter mapping, either to Java servlets or URL patterns.
There are a couple of possible methods: addFilterBefore(filter, class) adds a filter before the position of the specified filter class. addFilterAfter(filter, class) adds a filter after the position of the specified filter class. addFilterAt(filter, class) adds a filter at the location of the specified filter class.
In Spring boot, we have filters to filter the HTTP request; filter, in general, is used to intercept the request, i.e. HTTP request and the response from the client-side. By the use of a filter, we can perform two operations which can be done on response and request.
Add the annotation @ServletComponentScan to the spring boot main class, which will scan all servlet-related classes in the spring boot application context. You can use the url pattern to limit request control based on the request url. If you add multiple filters in a sequence, they will all run one at a time.
If you want to setup a third-party filter you can use FilterRegistrationBean
.
For example, the equivalent of 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>
These will be the two beans in your @Configuration
file:
@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();
}
The above was tested with Spring Boot 1.2.3.
Here is an example of one method of including a custom filter in a Spring Boot MVC application. Be sure to include the package in a component scan:
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 {}
}
There are three ways to add your filter,
@Component
@Bean
with Filter
type in Spring @Configuration
@Bean
with FilterRegistrationBean
type in Spring @Configuration
Either #1 or #2 will do if you want your filter applies to all requests without customization, use #3 otherwise. You don't need to specify component scan for #1 to work as long as you place your filter class in the same or sub-package of your SpringApplication
class. For #3, use along with #2 is only necessary when you want Spring to manage your filter class such as have it auto wired dependencies. It works just fine for me to new my filter which doesn't need any dependency autowiring/injection.
Although combining #2 and #3 works fine, I was surprised it doesn't end up with two filters applying twice. My guess is that Spring combines the two beans as one when it calls the same method to create both of them. In case you want to use #3 alone with authowiring, you can AutowireCapableBeanFactory
. The following is an example,
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;
}
There isn't a special annotation to denote a servlet filter. You just declare a @Bean
of type Filter
(or FilterRegistrationBean
). An example (adding a custom header to all responses) is in Boot's own EndpointWebMvcAutoConfiguration;
If you only declare a Filter
it will be applied to all requests. If you also add a FilterRegistrationBean
you can additionally specify individual servlets and url patterns to apply.
Note:
As of Spring Boot 1.4, FilterRegistrationBean
is not deprecated and simply moved packages from org.springframework.boot.context.embedded.FilterRegistrationBean
to org.springframework.boot.web.servlet.FilterRegistrationBean
UPDATE: 2017-12-16:
There are two simple ways to do this in Spring Boot 1.5.8.RELEASE and there isn't any need for XML.
First way:
If you do not have any specific URL pattern, you can use @Component like this (full code and details are here https://www.surasint.com/spring-boot-filter/):
@Component
public class ExampleFilter implements Filter {
...
}
Second way:
If you want to use URL patterns, you can use @WebFilter like this (full code and details are here https://www.surasint.com/spring-boot-filter-urlpattern/):
@WebFilter(urlPatterns = "/api/count")
public class ExampleFilter implements Filter {
...
}
But you also need to add @ServletComponentScan annotation in your @SpringBootApplication class:
@ServletComponentScan
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
...
}
Note that @Component is Spring's annotation, but @WebFilter is not. @WebFilter is Servlet 3 annotation.
Both ways, you just need a basic Spring Boot dependency in pom.xml (there isn't any need for an explicit Tomcat embedded 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>
WARNING: The first way, if the Controller in Spring Boot returns to a JSP file, the request will pass the filter twice.
While, in the second way, the request will pass the filter only once.
I prefer the second way, because it is more similar to default behavior in the Servlet specification.
You can see more test log here: https://www.surasint.com/spring-boot-webfilter-instead-of-component/
Here is an example of my custom Filter class:
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);
}
}
And I added it to the Spring Boot configuration by adding it to Configuration class as follows:
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;
}
}
From the Spring documentation,
Embedded servlet containers - Add a Servlet, Filter or Listener to an application
To add a Servlet, Filter, or Servlet *Listener provide a @Bean definition for it.
For example:
@Bean
public Filter compressFilter() {
CompressingFilter compressFilter = new CompressingFilter();
return compressFilter;
}
Add this @Bean
configuration to your @Configuration
class and the filter will be registered on startup.
Also you can add Servlets, Filters, and Listeners using classpath scanning,
@WebServlet, @WebFilter, and @WebListener annotated classes can be automatically registered with an embedded servlet container by annotating a @Configuration class with @ServletComponentScan and specifying the package(s) containing the components that you want to register. By default, @ServletComponentScan will scan from the package of the annotated class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With