1 Introduction
Sometimes we need in Spring Boot Servlet Web declare some custom applications Servlet Filter to deal with some logic. Simple systems such permission, the first request filter, preventing XSS attacks. This article deals explain how Spring Boot statement Custom Servlet Filter and define their respective scope and sequence applications.
2. Custom Filter
Some people may say that the statement is not achieved Servlet Filter Filter Interface Well, there is nothing to talk about! This is true, but many times we do not want our statement Filter action request to all. Even when a request needs the order according to the established through a plurality Filter. Next, I will be 11 to explain how to implement the above functions.
2.1 Filter statement
In Spring Boot only need to declare an implementation of javax.servlet.Filter
the interface Spring Bean on it. as follows:
@Configuration
public class FilterConfig {
@Bean
public Filter requestFilter() {
return (request, response, chain) -> {
//todo your business
};
}
@Bean
public Filter responseFilter() {
return (request, response, chain) -> {
//todo your business
};
}
}
复制代码
Very simple is not it? However, this approach can not guarantee the order, and act on all requests that intercepted Ant rules /*
. So we need to improve
Filter to achieve order of 2.2
To implement serialization, by means Spring provide @Order
comments or Ordered
interfaces. There is a pit: If you use @Order
annotations must be marked to comment on the specific class. In order to facilitate JavaConfig style statement. We can implement OrderedFilter
interface, which is Filter
the interface and the Ordered
composite interface, the final configuration as above
@Configuration
public class FilterConfig {
@Bean
public OrderedFilter responseFilter() {
return new ResponseFilter("/foo/*");
}
@Bean
public OrderedFilter requestFilter() {
return new RequestFilter("/foo/*");
}
}
复制代码
Filter the implementation of the rules is the smaller the number the more the first implementation . Before now Bean instantiated priority is the same.
Custom Filter scope 2.3
After the realization of the order we look at how to implement a custom Filter scope. Let's talk about ideas:
By
ServletRequest
acquiring the requested objectURI
, then the URI ANT style match on ANT can refer to my style of this one article . Match by performing a specific logic, otherwise skip that the Filter .
Here is a base abstract class for the flow to be fixed, leaving a hook as a function of the abstract method, only need to inherit the abstract base class implementation method can be a hook. In order to ensure that we remain the order of the base class implements OrderedFilter
an interface, we define a base class:
package cn.felord.springboot.filters;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
/**
* The type Abstract filter bean.
*
* @author Felordcn
* @since 11 :19
*/
public abstract class AbstractFilterBean implements OrderedFilter {
private Set<String> urlPatterns = new LinkedHashSet<>();
public AbstractFilterBean(String... urlPatterns) {
Collections.addAll(this.urlPatterns, urlPatterns);
}
/**
* 各自逻辑的函数钩子
*
* @param request the request
* @param response the response
*/
public abstract void internalHandler(ServletRequest request, ServletResponse response);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 进行ant匹配 true 执行具体的拦截逻辑 false 跳过
if (this.antMatch(request)) {
this.internalHandler(request, response);
}
chain.doFilter(request, response);
}
private boolean antMatch(ServletRequest request) {
Set<String> urlPatterns = getUrlPatterns();
if (!CollectionUtils.isEmpty(urlPatterns)) {
//进行Ant匹配处理
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String uri = httpServletRequest.getRequestURI();
Optional<String> any = urlPatterns.stream().filter(s -> {
AntPathMatcher antPathMatcher = new AntPathMatcher();
return antPathMatcher.match(s, uri);
}).findAny();
return any.isPresent();
}
// 如果 没有元素 表示全部匹配
return true;
}
public Set<String> getUrlPatterns() {
return urlPatterns;
}
}
复制代码
Let's achieve a specific Filter logic, the print request URI of the :
@Slf4j
public class RequestFilter extends AbstractFilterBean {
public RequestFilter(String... urlPatterns) {
super(urlPatterns);
}
@Override
public void internalHandler(ServletRequest request, ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
log.info("request from {}", httpServletRequest.getRequestURI());
}
@Override
public int getOrder() {
// 定义自己的优先级
return 0;
}
}
复制代码
Then define its good urlPatterns
and registering Spring IoC container on the line, and if desired a plurality performed in a certain order, following the section 2.2 methods provided on it.
3. Spring Boot mechanism
Way above our own making wheels. In fact, Spring Boot also offers Filter registration mechanism to implement the order of execution and statements scope. We may change the above logic:
package cn.felord.springboot.configuration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 使用 Spring Boot 提供的注册机制
*
* @author Felordcn
* @since 14:27
**/
@Configuration
@Slf4j
public class SpringFilterRegistrationConfig {
@Bean
public FilterRegistrationBean<Filter> responseFilter() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setName("responseFilter");
registrationBean.setOrder(2);
registrationBean.setFilter((request, response, chain) -> {
HttpServletResponse servletResponse = (HttpServletResponse) response;
log.info("response status {}", servletResponse.getStatus());
chain.doFilter(request,response);
});
registrationBean.addUrlPatterns("/foo/*");
return registrationBean;
}
@Bean
public FilterRegistrationBean<Filter> requestFilter() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setName("requestFilter");
registrationBean.setOrder(1);
registrationBean.setFilter((request, response, chain) -> {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
log.info("request from {}", httpServletRequest.getRequestURI());
chain.doFilter(request,response);
});
registrationBean.addUrlPatterns("/foo/*");
return registrationBean;
}
}
复制代码
3.1 points
FilterRegistrationBean
AndFilter
between one to one relationship.- If there is more
FilterRegistrationBean
need to call itsetName(String name)
its statement unique name, otherwise only the first successful registration is valid. - If the call sequence may be necessary to ensure by calling its
setOrder(int order)
setting method.
4. Summary
We customize and herein Spring Boot achieved using a custom Both options provide the Filter , although the way Spring Boot provide more convenient, but the way custom better reflect your understanding of object-oriented and improve your abstract ability. I hope a lot of attention, as usual. By public concern number: Felordcn reply f01 get herein DEMO .