前言
SpringBoot拦截器讲解。
一、编写拦截器
- 编写一个拦截器实现
HandlerInterceptor
接口 - 拦截器注册到容器中(实现
WebMvcConfigurer
的addInterceptors()
) - 指定拦截规则(注意,如果是拦截所有,静态资源也会被拦截】
编写一个实现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/**"); //放行的请求 }
二、拦截器的执行时机和原理
- 根据当前请求,找到
HandlerExecutionChain
(可以处理请求的handler以及handler的所有 拦截器) - 先来顺序执行 所有拦截器的
preHandle()
方法。
- 如果当前拦截器
preHandle()
返回为true
。则执行下一个拦截器的preHandle()
- 如果当前拦截器返回为
false
。直接倒序执行所有已经执行了的拦截器的afterCompletion();
。
- 如果任何一个拦截器返回
false
,直接跳出不执行目标方法。 - 所有拦截器都返回
true
,才执行目标方法。 - 倒序执行所有拦截器的
postHandle()
方法。 - 前面的步骤有任何异常都会直接倒序触发
afterCompletion()
。 - 页面成功渲染完成以后,也会倒序触发
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); } } } }
总结
以上就是拦截器的讲解。