目录

一、登录拦截器使用

1.编写一个拦截器实现HandlerInterceptor接口

2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)

3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】

二、拦截器的实现原理

1.springmvc处理逻辑参考博文

2.DispatcherServlet的doDispatch方法

3.执行拦截器的preHandle方法

4.倒叙执行所有拦截器的postHandle方法

5.页面成功渲染完成以后触发 afterCompletion

6.总结


一、登录拦截器使用

1.编写一个拦截器实现HandlerInterceptor接口

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/**
* 登录检查拦截器
* 1、配置好拦截器要拦截哪些请求
* 2、把这些配置放在容器中
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {/*** 目标方法执行之前执行*/@Overridepublic 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){//返回true就是 放行return true;}//拦截住。未登录。跳转到登录页request.setAttribute("msg","请先登录");//response.sendRedirect("/"); // 重定向(重定向无法传递数据)request.getRequestDispatcher("/").forward(request,response);// 转发可以传递参数return false;}/*** 目标方法执行完成以后,还未到页面渲染*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("postHandle执行{}",modelAndView);}/*** 页面渲染以后执行,或者方法执行失败执行*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("afterCompletion执行异常{}",ex);}
}

2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)

@Configuration
public class AdminWebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")  //所有请求都被拦截包括静态资源.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求}
}

3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】

如第2步,加上拦截的资源和放行的请求。

二、拦截器的实现原理

1.springmvc处理逻辑参考博文

springBoot-springMVC请求处理原理_私人博客,有需要请联系17854238061(vx同号)-CSDN博客

springmvc响应json与xml原理-详解数据响应与内容协商:

springboot-springmvc响应json与xml原理-详解数据响应与内容协商(长文预警,收藏慢啃)_私人博客,有需要请联系17854238061(vx同号)-CSDN博客

2.DispatcherServlet的doDispatch方法

DispatcherServlet的doDispatch方法是请求的入口。

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;try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.// 拿到请求处理器,里面有拦截器的数组HandlerInterceptor[]// 根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// 目标方法执行之前,会执行该方法// 遍历所有拦截器,执行拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 如果任何一个拦截器返回false。直接跳出不执行目标方法。return;}// 执行目标方法// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);// 倒叙执行所有拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}// 该方法是页面渲染逻辑,页面成功渲染完成以后,也会倒序触发 afterCompletionprocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {// 前面的步骤有任何异常也都会直接倒序触发 afterCompletion// 一切正常也会触发afterCompletiontriggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {// 前面的步骤有任何异常也都会直接倒序触发 afterCompletion// 一切正常也会触发afterCompletiontriggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
}

请求处理器,里面有拦截器的数组HandlerInterceptor[]

3.执行拦截器的preHandle方法

先来顺序执行 所有拦截器的 preHandle方法

① 如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle方法。

② 如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion方法。

如果任何一个拦截器返回false。直接跳出不执行目标方法。

// org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;
}
// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}

4.倒叙执行所有拦截器的postHandle方法

// org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}
}

5.页面成功渲染完成以后触发 afterCompletion

// org.springframework.web.servlet.DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isTraceEnabled()) {logger.trace("No view rendering, null ModelAndView returned.");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}if (mappedHandler != null) {// Exception (if any) is already handled..// 页面成功渲染完成以后触发 afterCompletionmappedHandler.triggerAfterCompletion(request, response, null);}
}

页面成功渲染完成以后,也会倒序触发 afterCompletion

// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}

6.总结

1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】

2、先来顺序执行 所有拦截器的 preHandle方法

(1)、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle

(2)、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;

3、如果任何一个拦截器返回false。直接跳出不执行目标方法

4、所有拦截器都返回True。则继续执行目标方法

5、目标方法执行完成之后,倒序执行所有拦截器的postHandle方法。

6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

7、页面成功渲染完成以后,也会倒序触发 afterCompletion

springboot-拦截器的实现、执行时机及原理相关推荐

  1. SpringBoot 拦截器 过滤器

    1.过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的.请求结束返回也是,是在servlet处理完后,返回给前端之前. 2.拦截器可以获取IOC容器中的各 ...

  2. springboot拦截器 跳过_springboot创建拦截器过程图解

    springboot创建拦截器过程图解 这篇文章主要介绍了springboot创建拦截器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一. ...

  3. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  4. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  5. SpringBoot拦截器与过滤器

    一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...

  6. springboot拦截器与过滤器详解

    前言 不管是传统的ssm项目,还是springboot项目,拦截器和过滤器在项目开发中都离不开,比如说对于ssm框架类的项目来说,许多登录逻辑的前置校验,黑白名单的检查,以及部分请求的数据分析等依然需 ...

  7. springboot文件上传和下载工具_SpringBoot图文教程7—SpringBoot拦截器的使用姿势这都有...

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  8. SpringBoot拦截器配置

    SpringBoot拦截器配置 自定义拦截器: com.example.mybatis2018.interceptor.MyInterCeptor package com.example.mybati ...

  9. Springboot 拦截器链 - 加载拦截器

    Springboot 拦截器链 - 加载拦截器 1.创建拦截器 // 创建拦截器需要实现 HandlerInterceptor 接口 @Slf4j public class HandleInterce ...

  10. Spring AOP源码解析-拦截器链的执行过程

    一.简介 在前面的两篇文章中,分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在得到了 bean 的代理对象,且通知也以合适的方式插在了目标方 ...

最新文章

  1. PrestaShop 网站漏洞修复如何修复
  2. 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)
  3. 对话功率谱与自相关函数
  4. 如何刪除GitHub中的repository
  5. ROS初学笔记 - C++11与PCL库冲突问题
  6. 自然语言处理之AI深度学习顶级实战
  7. Android studio导入项目提示The same input jar [*.jar] is specified twice
  8. 【三】版本之间穿梭切换
  9. 从视图到控制器的传值方法(表单)
  10. Flutter实战一Flutter聊天应用(十三)
  11. Infortrend大数据时代广电行业应用
  12. debian网络配置文件的写法
  13. nod32/ESET下載及更新
  14. 服务器虚拟机怎么安装win7系统教程,虚拟机怎么安装系统?VMware虚拟机安装Win7和win10图文详细教程...
  15. VMWare SCSI硬盘识别
  16. spring cloud alibaba全家桶之nacos
  17. 学习UI设计,哪些软件是必学的
  18. 京东数科java一面【过】
  19. 用python输出pi的近似值_Python-Pi近似
  20. 网桥调用iptables规则的善后处理

热门文章

  1. Netty ObjectPool对象池技术原理分析
  2. 倍数应用题后面需要带单位吗_数学应用题解答思路解析(附例题)
  3. keep 虚拟路线修改器_keep儿童版下载-keep儿童模式6.124.0手机版下载
  4. c语言不同指令意识,C语言必须理清的概念1
  5. python时间模块哪个好arrow模块_python库: arrow (时间)
  6. java代码调用python_Java调用Python
  7. C语言引用文件空格和换行,关于文件操作,碰到空格就换行
  8. go 自定义error怎么判断是否相等_Go Web 小技巧(二)GORM 使用自定义类型
  9. Linux磁盘格式化和挂载
  10. nginx 上传文件漏洞_nginx爆惊天漏洞 上传图片就能入侵服务器