SpringBoot实现拦截器和源码分析
1、定义拦截器
- preHandle方法实在是controller执行之前执行
- postHandle方法是在controller执行后执行
- afterCompletion方法在模板渲染后执行
示例:
/**
* 登录检查
* 1、配置好拦截器要拦截哪些请求
* 2、把这些配置放在容器中(之前在servlet的时候,实在xml里写,拦截哪些路径)
* 3、
*/
@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("拦截的请求路径是:"+requestURI);
//登录检查
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null){
//放行
return true;
}
//拦截住,就是未登录,跳转到登录页面 /就是当前项目页的首页
session.setAttribute("msg","请先登录");
response.sendRedirect("/");
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);
}
}
2、配置拦截器
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
/**
* 注入自定义拦截器
*/
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
InterceptorRegistration interceptor = registry.addInterceptor(loginInterceptor);
//添加 要拦截的路径 , /** 动态和静态资源 都会被拦截
InterceptorRegistration pathPatterns = interceptor.addPathPatterns("/**");
//添加 要放行的 路径
InterceptorRegistration pathPatterns1 = interceptor.excludePathPatterns("/", "/login","/css/**",
"/fonts/**","/images/**","/js/**");
}
}
3、拦截器源码分析
1、找到可以处理请求的handler 以及 handler的所有拦截器, HandlerExecutionChain 处理器执行链
LoginInterceptor是我们自定义的拦截器,而下面两个Conversion…和Resource…两个拦截器任何方法都会执行
mappedHandler = getHandler(processedRequest);
2、先来顺序执行 所有拦截器的 preHandle方法
-
1、如果当前拦截器prehandle返回为true。则执行下一个拦截器的preHandle
-
2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
(就是比如三个拦截器,前两个都放行,但是第三个没有放行,然后就会倒序执行 2-1 的afterCompletion)
源码中 for (int i = 0; i < this.interceptorList.size(); i++) ,所以是先来先服务
3、如果任何一个拦截器返回false。直接跳出不执行目标方法
if(!mappedHandler.applyPreHandle(processedRequest,response)){
return;
}
4、所有拦截器都返回True。执行目标方法
5、倒序执行所有拦截器的postHandle方法。
6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
7、页面成功渲染完成以后,也会倒序触发 afterCompletion