1、springboot添加拦截器
1、实现HandlerInterceptor 接口
package com.mubai.interceptor;
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;
/**
* 自定义拦截器.
*
* @author Mubai
* @date 2023/5/22 17:51
**/
@Slf4j
public class TestInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("testInterceptor=====preHandle======");
String type = request.getParameter("type");
if (type != null) {
// 放行
return true;
}
// 拦截服务.未登录,跳转到登录页
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("testInterceptor=====postHandle======");
}
/**
* 页面渲染之后
*
* @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("testInterceptor=====afterCompletion======");
}
}
2、配置拦截器
package com.mubai.config;
import com.mubai.interceptor.TestInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置拦截器.
*
* @author Mubai
* @date 2023/5/22 17:55
**/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/", "/test");
}
}
3、拦截器执行过程
1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
2、先来顺序执行 所有拦截器的 preHandle方法
2、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
3、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
4、如果任何一个拦截器返回false。直接跳出不执行目标方法
5、所有拦截器都返回True。执行目标方法
6、倒序执行所有拦截器的postHandle方法。
7、前面的步骤有任何异常都会直接倒序触发 afterCompletion
8、页面成功渲染完成以后,也会倒序触发 afterCompletion
4、执行器底层原理
1、拦截器究竟添加到哪里,我们在项目中的如下地方打一个断点进去一探究尽
跟随断点,往前面找,发现在如下地方,他把所有的拦截器加入到了处理器映射器中
2、接下来,我们看在请求目标资源时,怎么处理拦截的
1、我们发现他在DispatcherServlet的doDispatch方法中,发现在目标方法的前后调用了拦截器的三个方法,他先通过处理器映射器匹配到我们目标资源的拦截器链,
我们点进去看一下mappedHandler.applyPreHandle(processedRequest, response)的具体实现逻辑,方法一目了然,遍历拦截器链,从下标0开始调用每一个连接器的前置处理方法,如果前置方法返回true,则interceptorIndex=i,同时i++,
如果返回为false,则会触发triggerAfterCompletion方法,调用所有执行完前置方法的过滤器,具体逻辑如下:
从方法可以看出,他从interceptorIndex值开始往前执行,执行完之后返回false,再到DispatcherServlet中,直接return;不会调用目标方法。
如果返回为true,他会再调用完目标方法之后,则会进入到DispatcherServlet后置处理器方法,该方法从执行器链的最后一个元素开始,往前执行,方法很简单,这里就不赘述了。
最后会执行到拦截器链的afterCompletion方法,从interceptorIndex往前执行,详细过程如下,这里的interceptorIndex=链的长度