SpringBoot之拦截器

简介: SpringBoot之拦截器



前言

SpringBoot拦截器讲解。


一、编写拦截器

  1. 编写一个拦截器实现HandlerInterceptor接口
  2. 拦截器注册到容器中(实现WebMvcConfigureraddInterceptors()
  3. 指定拦截规则(注意,如果是拦截所有,静态资源也会被拦截】

编写一个实现HandlerInterceptor接口的拦截器:

/**
 * 登录检查
 * 1、配置好拦截器要拦截哪些请求
 * 2、把这些配置放在容器中
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目标方法执行之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        log.info("preHandle拦截的请求路径是{}",requestURI);
        //登录检查逻辑
        HttpSession session = request.getSession();
        Object loginUser = session.getAttribute("loginUser");
        if(loginUser != null){
            //放行
            return true;
        }
        //拦截住。未登录。跳转到登录页
        request.setAttribute("msg","请先登录");
//        re.sendRedirect("/");
        request.getRequestDispatcher("/").forward(request,response);
        return false;
    }
    /**
     * 目标方法执行完成以后
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行{}",modelAndView);
    }
    /**
     * 页面渲染以后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行异常{}",ex);
    }
}

拦截器注册到容器中 ,指定拦截规则:

/**
 * 1、编写一个拦截器实现HandlerInterceptor接口
 * 2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
 * 3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
 */
@Configuration
public class AdminWebConfig implements WebMvcConfigurer{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())//拦截器注册到容器中
                .addPathPatterns("/**")  //所有请求都被拦截包括静态资源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**",
                        "/js/**","/aa/**"); //放行的请求
}

二、拦截器的执行时机和原理

  1. 根据当前请求,找到HandlerExecutionChain(可以处理请求的handler以及handler的所有 拦截器)
  2. 先来顺序执行 所有拦截器的preHandle()方法。
  • 如果当前拦截器preHandle()返回为true。则执行下一个拦截器的preHandle()
  • 如果当前拦截器返回为false。直接倒序执行所有已经执行了的拦截器的 afterCompletion();
  1. 如果任何一个拦截器返回false,直接跳出不执行目标方法。
  2. 所有拦截器都返回true,才执行目标方法。
  3. 倒序执行所有拦截器的postHandle()方法。
  4. 前面的步骤有任何异常都会直接倒序触发 afterCompletion()
  5. 页面成功渲染完成以后,也会倒序触发 afterCompletion()

拦截器我在SpringMVC中讲解过一些:SpringMVC之拦截器

DispatcherServlet中涉及到HandlerInterceptor的地方:

public class DispatcherServlet extends FrameworkServlet {
    ...
  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
      ModelAndView mv = null;
      Exception dispatchException = null;
              ...
                //该方法内调用HandlerInterceptor的preHandle()
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          return;
        }
        // Actually invoke the handler.
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
              ...
                //该方法内调用HandlerInterceptor的postHandle()
        mappedHandler.applyPostHandle(processedRequest, response, mv);
      }     
          processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler,
          new NestedServletException("Handler processing failed", err));
    }
    finally {
      ...
    }
  }
  private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
    if (mappedHandler != null) {
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
      mappedHandler.triggerAfterCompletion(request, response, ex);
    }
    throw ex;
  }
  private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable Exception exception) throws Exception {
        ...
    if (mappedHandler != null) {
            //该方法内调用HandlerInterceptor接口的afterCompletion方法
      // Exception (if any) is already handled..
      mappedHandler.triggerAfterCompletion(request, response, null);
    }
  }
}
public class HandlerExecutionChain {
    ...
  boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for (int i = 0; i < this.interceptorList.size(); i++) {
      HandlerInterceptor interceptor = this.interceptorList.get(i);
            //HandlerInterceptor的preHandle方法
      if (!interceptor.preHandle(request, response, this.handler)) {
        triggerAfterCompletion(request, response, null);
        return false;
      }
      this.interceptorIndex = i;
    }
    return true;
  }
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
      throws Exception {
    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
      HandlerInterceptor interceptor = this.interceptorList.get(i);
            //HandlerInterceptor接口的postHandle方法
      interceptor.postHandle(request, response, this.handler, mv);
    }
  }
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    for (int i = this.interceptorIndex; i >= 0; i--) {
      HandlerInterceptor interceptor = this.interceptorList.get(i);
      try {
                //HandlerInterceptor接口的afterCompletion方法
        interceptor.afterCompletion(request, response, this.handler, ex);
      }
      catch (Throwable ex2) {
        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
      }
    }
  }
}

总结

以上就是拦截器的讲解。

相关文章
|
5天前
|
Java
SpringBoot中的拦截器 interceptor
SpringBoot中的拦截器 interceptor
23 0
|
9月前
|
前端开发 Java 数据安全/隐私保护
SpringBoot配置拦截器
SpringBoot配置拦截器
115 0
|
9月前
|
Java 容器
Springboot中拦截器的使用
Springboot中拦截器的使用
32 0
|
9月前
|
Java 应用服务中间件 API
【SpringBoot】过滤器 | 拦截器
【SpringBoot】过滤器 | 拦截器
94 0
|
10月前
|
Java Spring
springboot拦截器
springboot拦截器
|
11月前
|
前端开发 Java 数据安全/隐私保护
【SpringBoot学习笔记 十】深入理解SpringBoot拦截器
【SpringBoot学习笔记 十】深入理解SpringBoot拦截器
124 0
|
11月前
|
Java
springboot中基于springmvc的拦截器的实现
springboot中基于springmvc的拦截器的实现
74 0
|
前端开发 Java API
springboot下使用过滤器与拦截器
springboot下使用过滤器与拦截器
SpringBoot自定义拦截器
在springboot中有一个叫做ResourceProperties的类,里面就定义了静态资源的默认查找路径: 默认的静态资源路径为: • classpath:/META-INF/resources/ • classpath:/resources/ • classpath:/static/ • classpath:/public 在项目中创建路径进行测试 在static目录下创建index.html文件
|
JSON Java 数据格式
SpringBoot——SpringBoot中使用拦截器
SpringBoot——SpringBoot中使用拦截器
SpringBoot——SpringBoot中使用拦截器