Spring Boot 2 combat: how to customize Servlet Filter

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.Filterthe 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 @Ordercomments or Orderedinterfaces. There is a pit: If you use @Orderannotations must be marked to comment on the specific class. In order to facilitate JavaConfig style statement. We can implement OrderedFilterinterface, which is Filterthe interface and the Orderedcomposite 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 ServletRequestacquiring the requested object URI, 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 OrderedFilteran 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 urlPatternsand 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

  • FilterRegistrationBeanAnd Filterbetween one to one relationship.
  • If there is more FilterRegistrationBeanneed to call it setName(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 .

Guess you like

Origin juejin.im/post/5e09c64af265da33f40f3891