学习参考:https://www.jianshu.com/p/51c5193b5883
一、自定义一个拦截器
1、实现拦截器
- 实现
HandlerInterceptor
接口 - 根据需求重写
preHandle()
,postHandle()
,afterCompletion()
方法
package com.mystudy.springboot.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录校验
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 方法在请求之前开始调用运行
* @param request
* @param response
* @param handler
* @return 返回true,表示继续流程,调用下一个拦截器或者处理器。返回false,表示流程中断,通过response产生响应。
* 当方法返回false,后边的所有拦截器包括postHandle()、afterCompletion()都不在运行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object userName = request.getSession().getAttribute("userName");
if(userName==null){
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
// response.sendRedirect(request.getContextPath()+"/");
return false;
}
return true;
}
/**
* 方法在当前请求进行处理之后,就是controller运行完成之后被调用
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 方法在整个请求结束之后,就是在视图渲染完成后运行
* 这个方法的主要作用是用于进行资源清理工作的。
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2、注册拦截器
- 实现
WebMvcConfigurer
接口 - 重写
addInterceptor()
方法
package com.mystudy.springboot.config;
import com.mystudy.springboot.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
/**
* 注册拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器
InterceptorRegistration addInterceptor = registry.addInterceptor(new LoginInterceptor());
// 配置拦截器路径
addInterceptor.addPathPatterns("/**");
// 配置不拦截路径,SpringBoot2.0以后静态资源映射会被拦截器拦截,所以需要取消静态资源的拦截
// 取消webjars资源拦截器: webjars/**
// 取消类路径下静态资源拦截: /js/** /css/** /img/**
// 或者js、css、img放在同一文件夹asserts下, 则是:/asserts/**
addInterceptor.excludePathPatterns("/user/login","/","/index.html","/asserts/**","/webjars/**");
}
}
二、原理
1、工作原理
拦截器不是Filter,却实现了Filter的功能,其原理在于:
- 所有的拦截器(Interceptor)和处理器(Handler)都注册在HandlerMapping中。
- Spring MVC中所有的请求都是由DispatcherServlet分发的。
- 当请求进入DispatcherServlet.doDispatch()时候,首先会得到处理该请求的Handler(即Controller中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
2、拦截器工作流程
一个拦截器,只有preHandle方法返回true,postHandle、afterCompletion才有可能被执行;
如果preHandle方法返回false,则该拦截器的postHandle、afterCompletion必然不会被执行。
1)拦截器执行流程
Interceptor1.preHandle → Interceptor2.preHandle → Controller处理请求
→ Interceptor2.postHandle → Interceptor1.postHandle → 渲染视图
→ Interceptor2.afterCompletion → Interceptor1.afterCompletion
注意:两个拦截器在执行preHandle
方法和执行postHandle
、afterCompletion
方法时,顺序是颠倒的。
2)和Filter共存时的执行顺序
拦截器是在DispatcherServlet这个servlet中执行的,因此所有的请求最先进入Filter,最后离开Filter。其顺序如下。
Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter
网友评论