Detailed explanation of SpringBoot&Filter

Posted by surion on Thu, 28 Oct 2021 08:07:22 +0200

Detailed explanation of springboot & filter

In fact, the filter is to intercept web resources, and then hand them over to the next filter or servlet for processing. It is usually used to intercept request s for processing, or to intercept the returned response

The general flow chart is as follows

Application scenario

  • automatic logon

  • Uniform coding format

  • Access control

  • Sensitive character filtering, etc

  • ......

1. Use of Filter

To use filter, we need to write a method to inherit the filter class. We write the following two filter classes. The first is the FirstFilter class. The smaller the number in @ Order means that it is filtered by the filter first, @ WebFilter means that it is a filter class and inject this class into the container.

be careful:

    SpringBoot implements Filter in two ways:

  1. The custom Filter is injected through the FilterRegistrationBean class; (not recommended)

  2. Custom Filter implements the interface Filter method and @ WebFilter injection.

FirstFilter

@Order(1)
@WebFilter(filterName="firstFilter", urlPatterns="/*")
public class FirstFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("first filter 1111111111111111111");
        chain.doFilter(request, response);
        System.out.println("first filter 2222222222222222222");
    }

    @Override
    public void destroy() {

    }
}

SecondFilter

@Order(2)
@WebFilter(filterName="secondFilter", urlPatterns="/*")
public class SecondFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("second filter 1=============================");
        System.out.println("before:" + response);
        chain.doFilter(request, response);
        System.out.println("after:" + response);
        System.out.println("second filter 2=============================");

    }

    @Override
    public void destroy() {

    }
}

TestController

@RestController
public class TestController {

    @GetMapping("/test1")
    public String test1() {
        System.out.println("method in controller");
        return "test1";
    }

}

postman test: http://localhost:8080/test1

Output results:

first filter 1111111111111111111
second filter 1=============================
before:org.apache.catalina.connector.ResponseFacade@1d2aafd8
method in controller
after:org.apache.catalina.connector.ResponseFacade@1d2aafd8
second filter 2=============================
first filter 2222222222222222222

Process:

Summary:

We can see the process of code execution. First, the request is intercepted by the first filter, print the first filter 1, and then execute chain.doFilter(request, response). This sentence means that the request will be forwarded to the next object in the filter chain, that is, the secondfilter, so print the second filter 1 in the secondfilter, Next, execute the chain.dofilter() method in the secondfilter to forward the request to the next object. Since there are no other filters, it will be forwarded to the controller, print out the method in controller in the controller class, then call the print of the secondfilter ("second filter 2") in the memory stack, and then call the print of the firstfilter in the memory stack( "First filter 1"). Therefore, if you do not add chain.doFilter(req, rep) to the doFilter method of your implemented filter class, it is absolutely impossible. That will cause the request to go no further in this filter and never enter the controller.

We can also print("before:" + response) and print("after:" + response) These two places break the point, then debug, you will find what is in response in before, and there is test1 string in response in after, that is, the return value of controller class test1 method has been added to response, so if you want to filter the response of request, then it must be chain.doFi. Write your logic after lter (RES, Rep).

2. @ WebFilter annotation description

@ WebFilter is used to declare a class as a filter. The annotation will be processed by the container during deployment. The container will deploy the corresponding class as a filter according to the specific attribute configuration. The annotation has some common attributes given in the following table (all the following attributes are optional, but value, urlPatterns and servletNames must contain at least one, and value and urlPatterns cannot coexist. If they are specified at the same time, the value of value is usually ignored.)

@Common properties of WebFilter

Attribute nametypeexplain
filterName String Specifies the name attribute of the filter, which is equivalent to the < filter name > tag
value String[] This attribute is equivalent to the < URL pattern > tag, but both should not be used at the same time
urlPatterns String[] Specifies the URL matching pattern for a set of filters. Equivalent to < URL pattern > tags.
servletNames String[] Servlet used to specify filtering. The value is the value of the name attribute in @ WebServlet or the value of < servlet name > in web.xml.
dispatcherTypes DispatcherType[] Specifies the forwarding mode of the filter. Specific values INCLUDE: ASYNC, ERROR, FORWARD, INCLUDE, REQUEST
initParams WebInitParam[] It is used to set some initialization parameters of the filter class, which is equivalent to the < init param > tag
asyncSupported Boolean Declare whether the filter supports asynchronous operation mode, which is equivalent to the < async supported > tag
description String The description of the filter is equivalent to the < description > tag
displayName String The filter display name, which is usually used with tools, is equivalent to the < display name > tag

3. Practical application of responsibility chain model

How are Filter and FilterChain implemented in the responsibility chain mode? Customize the implementation and use the Filter mode to simulate

Filter interface

public interface Filter {
    /**
     * filter
     * @param request Request object
     * @param response Return object
     */
    public void doFilter(Request request, Response response, FilterChain chain);

}

FilterChain class {filter chain}

/**
 * @Desc: TODO Filter chain [key members of the implementation responsibility chain model]
 */
public class FilterChain implements Filter {

    /**
     * Filter list
     */
    private List<Filter> filters = new ArrayList<>();

    int index = 0;

    /**
     * Add filter
     * @param filter
     */
    public FilterChain addFilter(Filter filter) {
        filters.add(filter);
        return this;
    }

    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        if(index == filters.size()) {
            /**
             * Actually process the request (start processing the controller business logic at this time)
             */
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request, response, chain);
    }

}

Request class and Response class

public class Request {
    public String requestStr;
}
public class Response {
    public String responseStr;
}

Implementation class (filter required in business, for example)

EncodeFilter {set unified coding}

public class EncodeFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        request.requestStr = request.requestStr + "  Set encoding UTF-8";
        System.out.println("EncodeFilter request Str:" + request.requestStr);
        chain.doFilter(request, response, chain);
        response.responseStr = response.responseStr + "-------------Set encoding UTF-8";
        System.out.println("EncodeFilter response Str:" + response.responseStr);
    }
}

VerifyParameterFilter {parameter verification}

public class VerifyParameterFilter  implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        request.requestStr = request.requestStr + "  Parameter validation succeeded";
        System.out.println("VerifyParameterFilter request str:" + request.requestStr);
        chain.doFilter(request, response, chain);
        response.responseStr = response.responseStr + "======================";
        System.out.println("VerifyParameterFilter response str:" + response.responseStr);
    }
}

test

public class FilterTest {
    public static void main(String[] args) {
        String msg = "Zhang San";
        Request request = new Request();
        request.requestStr = msg;
        Response response = new Response();
        response.responseStr = "success *****";

        FilterChain fc = new FilterChain();
        fc.addFilter(new EncodeFilter())
                .addFilter(new VerifyParameterFilter())
                .doFilter(request, response, fc);
    }
}

result:

EncodeFilter request Str:Zhang San sets the code UTF-8
VerifyParameterFilter request str:Zhang San sets the code UTF-8  Parameter validation succeeded
VerifyParameterFilter response str:success *****======================
EncodeFilter response Str:success *****======================-------------Set encoding UTF-8

summary

  1. Filter is used to intercept requests, filter before requests, verify permissions, log records, unified coding, etc

  2. All Filter unification forms a chain in FilterChain, and the call is also unified by FilterChain to ensure the implementation of the chain mode.

  3. Responsibility chain mode is an important design mode, such as Filter mode in Servlet and Plugin mode in Mybatis

Topics: Spring Boot