The Springboo project quickly implements the interceptor function

foreword

The previous article shared the Springboot project to quickly implement the filter function . This article will continue with a set of interceptors. After careful study, you will find that the functions of interceptors and filters are very similar, which can be understood as a part of aspect-oriented programming. a specific implementation. The following will sort out its functional characteristics, working principle, core classes involved, and specific implementation methods, so that in the actual business development process, you can choose the appropriate implementation request according to actual needs.

Environment configuration

jdk version: 1.8

Development tools: Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

Introduction to HandleInterceptor

Interceptor is just a concept in java, and there is no specific implementation or standard. Usually, the interceptor of java web refers to the HandleInterceptor interface, which is a set of interception mechanism provided by Spring MVC, which can be processed in the controller After the request and the response processing results, the request information and response results are intercepted; but the specific request information and response results cannot be modified; the concept of Spring MVC interceptors is very similar to that of servlet filters, but there are differences in the order of execution Different, the following will focus on the introduction; in essence, the interceptor mechanism of SpringMVC is a specific implementation of AOP (aspect-oriented programming), which can be used by users to horizontally extract some common services in the actual business, but with Like the Filter of the servlet, it has certain limitations. For example, it can intercept the request information and response results, but cannot modify the specific request information and response results; it can intercept the methods of the controller layer, but cannot intercept the methods of the service layer;

working principle

If you put the filter and the interceptor together to analyze its working principle, you need to clarify one thing again: the fully qualified class name of the Filter interface is javax.servlet.Filter, and the fully qualified class name of the HandleInterceptor interface is org.springframework. web.servlet.HandlerInterceptor, it can be seen from here that Filter is an interface in servlet, and HandleInterceptor is a new interface in Spring. The two sources are completely different, but their functions are very similar, so put them in What wonderful things will happen together?

1. Filter 1, filter 2, interception 1, and interception 2 objects will complete the bean registration during the startup of the Spring container;

2. When the client initiates an http request to the server, before the request reaches the specific controller method, it will be processed by the filter and the interceptor first, and the execution time of the filter is earlier than that of the interceptor; the same as the filter, If the current request matches multiple interceptors, an interceptor chain will be formed. According to the default or specified priority, each interceptor object will be processed in turn before reaching the specific controller method;

3. After arriving at the specific controller method, start business processing; after getting the business processing result, the response result will also be processed by all filters and interceptors when the request comes in. The difference is that the order is completely opposite to when the request comes in, that is, advanced back out;

Method to realize

1. Implement the org.springframework.web.servlet.HandlerInterceptor interface;

2. Inherit the org.springframework.web.servlet.handler.HandlerInterceptorAdapter class;

core class

HandlerInterceptor

HandlerInterceptor is a standard interface provided by SpringMVC to implement the interceptor function. There are three methods in the interface:

1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler), the method will be called before the request is processed. This method is executed first in the Interceptor class, and is used to perform some pre-initialization operations or preprocess the current request, and also make some judgments to determine whether the request should continue. The return value of this method is Boolean type; when it returns false, it means that the request is over, and the subsequent Interceptor and Controller will not be executed; when it returns true, it will continue to call the preHandle method of the next Interceptor, if it is already When the last Interceptor is called, the Controller method of the current request will be called;

2. The postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) method is executed after the current request is processed, that is, after the Controller method is called, but it will be called before the DispatcherServlet returns the view to render, so we can use this In the method, the ModelAndView object processed by the Controller is operated;

3. The afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) method will only be executed when the return value of the preHandle method of the corresponding Interceptor class is true; this method will be executed after the entire request is completed, that is, rendered in the DispatcherServlet After the corresponding view is executed, it is mainly used to clean up or release resources.

HandlerInterceptorAdapter

HandlerInterceptorAdapter is an abstract class that implements the AsyncHandlerInterceptor interface, and the AsyncHandlerInterceptor interface inherits from HandlerInterceptor, so it can be considered that HandlerInterceptorAdapter implements the HandlerInterceptor interface, but HandlerInterceptorAdapter is an abstract class that is not actually implemented, so it is implementing the interceptor The two ways of function function are essentially one;

Code

Define two interceptors: MyInterceptor1 and MyInterceptor2, and analyze how the preHandle(), postHandle(), and afterCompletion() of the HandlerInterceptor interface work through a completed request.

1. Define and register two interceptors: MyInterceptor1 and MyInterceptor2, set the interception path of the interceptor to /person/get*, and the priority of myInterceptor2 is higher than that of myInterceptor1;

2. Initiate an http request (URL:/person/get);

3. The /person/get request will execute the preHandler() method of MyInterceptor1 and MyInterceptor2 before executing PersonController#getPerson();

4. If the preHandler() methods of MyInterceptor1 and MyInterceptor2 return true, it will execute to PersonController#getPerson();

5. After the execution of PersonController#getPerson() is completed, the postHandle() method of MyInterceptor1 and MyInterceptor2 triggers the execution before returning the view rendering object;

6. Then after the entire request is processed, the afterCompletion() method of MyInterceptor1 and MyInterceptor2 triggers execution;

PersonController.java

@Controller
@RequestMapping("/person")
@Slf4j
public class PersonController {
    @Autowired
    private IPersonService personService;
    @GetMapping("/get")
    @ResponseBody
    public Person getPerson(Integer id) {
        Person person = this.personService.get(id);
        log.info("//查询person详情执行完成");
        return person;
    }
}

定义WebConfig类实现WebMvcConfigurer接口,实现addInterceptors(),完成拦截器的注册以及设置好拦截路径和优先级顺序;

@Configuration
public class WebConfig  implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new MyInterceptor2())
        .addPathPatterns("/person/get*")
        .order(1);
         registry.addInterceptor(new MyInterceptor1())
        .addPathPatterns("/person/get*")//设置拦截请求路径;*是通配符;
        .order(2)//设置拦截器对象的优先级,如果有多个拦截器对象,设置数字越小,优先级越高;
        .excludePathPatterns("/test");//设置排除拦截的请求路径;
    }
}

定义MyInterceptor1类实现HandlerInterceptor接口

@Slf4j
public class MyInterceptor1 implements HandlerInterceptor {
    //preHandle方法在请求处理之前被调用;当返回true,则表示可以继续后续请求处理;当返回false,则表示请求结束;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("//myInterceptor1的preHandle方法开始执行");
        log.info("//请求路径:{}",request.getRequestURI());
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        log.info("//拦截类:{},方法:{}",handlerMethod.getBean().getClass().getName(),handlerMethod.getMethod().getName());
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String parameterName = parameterNames.nextElement();
            String parameterValue = request.getParameter(parameterName);
            log.info("//请求参数>{}:{}",parameterName,parameterValue);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("//myInterceptor1的postHandle方法开始执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("//myInterceptor1的afterCompletion方法开始执行");
    }
}

定义MyInterceptor2,继承HandlerInterceptorAdapter抽象类,重写HandlerInterceptorAdapter类的方法;

@Slf4j
public class MyInterceptor2 extends HandlerInterceptorAdapter {
    //preHandle方法在请求处理之前被调用;当返回true,则表示可以继续后续请求处理;当返回false,则表示请求结束;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("//myInterceptor1的preHandle方法开始执行");
        log.info("//请求路径:{}",request.getRequestURI());
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        log.info("//拦截类:{},方法:{}",handlerMethod.getBean().getClass().getName(),handlerMethod.getMethod().getName());
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String parameterName = parameterNames.nextElement();
            String parameterValue = request.getParameter(parameterName);
            log.info("//请求参数>{}:{}",parameterName,parameterValue);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("//myInterceptor1的postHandle方法开始执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("//myInterceptor1的afterCompletion方法开始执行");
    }

结果验证

Filter与HandleInterceptor的执行顺序:在请求处理阶段,先经过Filter然后再经过HandleInterceptor,在响应处理阶段,先经过HandleInterceptor,再经过Filter,即先进后出;

总结

拦截器的功能与Filter比较类似,实现方式也比较简单,需要特别注意的是拦截器的执行时机稍晚于过滤器。那么Spring的AOP与过滤器、拦截器相比,又有哪些不同和需要注意的事项呢?下一篇文章会把这个坑给填上。

Guess you like

Origin blog.csdn.net/fox9916/article/details/129691345
Recommended