Summary of Filters and Interceptors

        Filters and interceptors are not often used in daily business development. They have been encountered occasionally in recent projects. A systematic study of filters and interceptors has been conducted, which is summarized as follows.

1. Filter

        1.1 What is a filter

                Filter is one of the advanced features of Servlet, which is a Java class that implements the Filter interface. Its basic function is to intervene in the call of servlet, and add some specific functions in the process of servlet request and response. The functions that can be implemented using filters include: unified encoding, URL-level permission access control, filtering sensitive words, and compressing request information.

        1.2 Execution of filters

                


   

1.3 Filter interface

        By looking at the Filter interface code, there are three methods:

           

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

       init(FilterConfig conf) method : used to initialize the filter, and the web container will automatically call this method when the web project starts.

        doFilter(ServletRequest request, SerlvetResponse response, FilterChain chain) method : When the request and response are intercepted by the filter, they will be handed over to doFilter for processing: the two parameters are the intercepted request and response objects, and you can use the doFliter method of chain to let go.

        destroy() method : used to release the resources opened by closing the Filter object. When the web project is closed, this method is automatically called by the web container.

1.4 How to develop a Filter

        It is relatively simple to develop a filter. The first step is to implement the Filter interface, and the second step is to configure the filter

Develop a simple filter code as follows:

package com.lsl.mylsl.filter;

import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@Component
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        //获取filter名字
        String filterName = filterConfig.getFilterName();

        //获取filter里配置的init-param配置指定参数的值,如果参数不存在,则返回 null
        String email = filterConfig.getInitParameter("email");

        //获取filter里配置的init-param配置所有参数值,如果过滤器没有初始化参数,则返回一个空的 Enumeration
        Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();

        //返回对调用者在其中执行操作的 ServletContext 的引用。
        ServletContext servletContext = filterConfig.getServletContext();
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        //统一编码处理
        httpRequest.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("text/html;charset=UTF-8");

        //添加name属性
        httpRequest.setAttribute("name", "tom");

        //获取请求中的所有cookie
        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null) {
            StringBuilder sb = new StringBuilder();
            for (Cookie cookie : cookies) {
                String cookieName = cookie.getName();
                String cookieValue = cookie.getValue();
                //设置cookie的相关属性
                ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
                httpResponse.addHeader(HttpHeaders.SET_COOKIE, lastCookie.toString());
            }

            filterChain.doFilter(httpRequest, httpResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

The second step is to configure the filter:

There are three ways to configure filter         , and the above code is one of them (annotation configuration).

               The first type: configure in web.xml

                

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
    <init-param>
        <param-name>email</param-name>
        <param-value>15***[email protected]</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter> configuration

Fliter-name: refers to the name of the filter

filter-class: the full class name of the filter

init-param: Used to specify initialization parameters for the filter, and its sub-elements specify the name of the parameter

<filter-mapping> configuration

 filter-name: the filter-name you declared in <filter>

url-patten: Set the request path intercepted by the filter (the URL pattern associated with the filter)

The second type: annotation configuration, this is relatively simple, define the annotation on the filter

        

@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})

The third method: using the configuration class, the relevant code is as follows

        

package com.lsl.mylsl.filter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyFilterConfig {

    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean fb = new FilterRegistrationBean();
        //设置filter启动顺序
        fb.setOrder(1);
        fb.setFilter(new MyFilter());
        fb.addInitParameter("email","15***[email protected]");
        //设置拦截请求规则,这里拦截所有请求
        fb.addUrlPatterns("/*");
        return fb;
    }
}

Here are the advantages and disadvantages of these three filter configurations :

        The first type of xml configuration needs to be written in xml, but now most of them are developed by springboot projects, which focus on annotations and light configuration, and are not used much now. If multiple filters are configured in xml, they will work in sequence from top to bottom.

        The second annotation configuration is relatively simple to write, but it has a disadvantage that multiple filters cannot control the sequence. If you want to use this annotation, but still want to control the order of the filters, there is a saying on the Internet that the order of the first letters of the filter names is used to determine the order. For example, if there are multiple filters whose names are AdminFilter and UserFilter, then the former takes effect first. The latter takes effect later.

        The third type of configuration configuration, I personally prefer this (of course, if it is a simple filter, it is the easiest and most convenient to use annotations), it has all the functions of xml configuration. You can define the startup sequence, initialization parameters, etc.

2. Interceptor Interceptor

        2.1 What is an interceptor

        Spring MVCInterceptor The interceptor ( )  in  is similar to the filter ( ) in  ServLetFilter  , it is mainly used to intercept user requests and make corresponding processing. For example, the interceptor can perform authority verification, record the log of request information, and judge whether the user is logged in or not.

        2.2 Working principle of the interceptor  

        An interceptor, only if the preHandle method returns true, postHandle and afterCompletion may be executed; if the preHandle method returns false, then the interceptor's postHandle and afterCompletion will not be executed. The interceptor is not a Filter, but it realizes the function of a Filter. The principle is:

        All interceptors (Interceptor) and processors (Handler) are registered in HandlerMapping.
All requests in Spring MVC are dispatched by DispatcherServlet.
        When a request enters DispatcherServlet.doDispatch(), it will first get the Handler that handles the request (that is, the corresponding method in the Controller) and all interceptors that intercept the request. The interceptor is called here to start working.

        2.3 Interceptor usage scenarios                

        Interceptors are essentially aspect-oriented programming (AOP). Functions that meet cross-cutting concerns can be implemented in interceptors. The main application scenarios include:

        -Login verification, to determine whether the user is logged in or not.
        -Permission verification, to determine whether the user has permission to access resources, such as verifying the token
        -Log record, record the request operation log (user ip, access time, etc.), so as to count the number of request visits.
        - Handles cookies, localization, internationalization, theming, etc.
        - Performance monitoring, monitoring request processing time, etc.

        2.4, interceptor interface HandlerInterceptor

        

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

        As can be seen from the code, the interceptor interface has three methods, the respective functions are:

                preHandle method : called the preprocessing method, this method is executed before the controller method (MyController method), the user's request arrives at this method first, in this method you can obtain the requested information and verify whether the request meets the requirements. To verify whether the user is logged in, verify whether the user has permission to access a certain link address (url). If it returns true, it will be released, and if it returns false, it will be intercepted.

                postHandle method : called post-processing method. Executed after the method in the controller. The return value mv of the processor method can be obtained, and the data and views in the mv can be modified. Can affect the final execution result. Mainly to make secondary corrections to the original execution results

                afterCompletion method : The last method executed, executed after the page is rendered. It is executed after the request processing is completed. The framework stipulates that when your view processing is completed, the view is forworded. The processing of the task request is completed. Generally, when doing resource recovery work, some objects are created during the program request process. You can delete it here, let’s reclaim the occupied memory

        2.5 Developing an interceptor

                It also takes 2 steps to develop an interceptor. The first step is to implement the HandlerInterceptor interface to define an interceptor. The second step is to configure the interceptor.

        The first step is to define an interceptor

        

package com.lsl.mylsl.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        
        //在拦截的请求了添加属性,在对应请求的controller中的request中就可以获取该参数了
        //比如String userName = (String)request.getAttribute("userName");
        request.setAttribute("userName","lsl");
        
        //获取cookie
        Cookie[] cookies = request.getCookies();

        //设置header属性
        response.addHeader("SameSite","Lax");
        
        //添加cookie
        Cookie cookie = new Cookie("name","lsl");
        response.addCookie(cookie);
        
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

        

        Step 2: Configure the interceptor

        

package com.lsl.mylsl.interceptor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截器配置类
 */
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {

    /**
     * 配置拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(myInterceptor())
                .addPathPatterns("/api/lsl/**")//需要拦截的请求
                .addPathPatterns("/api/mjx/**")//需要拦截的请求
                .excludePathPatterns("/api/debug/**")//不拦截的请求
                .excludePathPatterns("api/lsl/getName");//不拦截的请求
    }

    /**
     * 注入拦截器到spring容器
     * @return
     */
    @Bean
    public MyInterceptor myInterceptor(){
        return new MyInterceptor();
    }
}

3. The difference between filters and interceptors

1. The interceptor is based on the java reflection mechanism, while the filter is based on the function callback (responsibility chain)

2. The filter depends on the servlet container, while the interceptor does not depend on the servlet container

3. Interceptors can only work on action requests, while filters can work on almost all requests

4. Interceptors can access objects in the action context and value stack, while filters cannot

5. In the life cycle of the action, the interceptor can be called multiple times, while the filter can only be called once when the container is initialized

6. The interceptor can obtain each bean in the IOC container, but the filter cannot. This is very important. A service can be injected into the interceptor to call the business logic.

7. The filter belongs to Servlet, while the interceptor belongs to springmvc

8. Filters can intercept all requests, including requests to access static resources. Interceptors can only intercept action requests, that is, requests to access controllers.

Popular understanding:
(1) Filter (Filter): When you have a bunch of things, you only want to select certain things that meet your requirements. The tool for defining these requirements is the filter. (Understanding: just take a B from a bunch of letters)
(2) Interceptor (Interceptor): When a process is in progress, you want to intervene in its progress, or even terminate it, which is what an interceptor does. (Understanding: It is a bunch of letters, intervene in it, pass the verification less, and do something else by the way

Diagram of Filters and Interceptors

insert image description here

Guess you like

Origin blog.csdn.net/dhklsl/article/details/127533485
Recommended