一、使用场景
比如对特定的URL检查用户是否登录,打印处理用户请求耗时的时间等,可以用拦截器来实现。
二、拦截器使用
定义拦截器,需要实现 HandlerInterceptor 接口,接口中有3个方法
- preHandle:在DispatcherServlet处理请求执行之前被调用
- postHandle:在DispatcherServlet处理请求执行完成后,生成视图之前被调用(还未渲染页面)
- afterCompletion:在DispatcherServlet处理请求执行完成后,且已生成视图被调用,可以用于清除资源(已渲染了页面)
)2.1 创建自定义拦截器 MyInterceptor 类
@Slf4j public class MyInterceptor implements HandlerInterceptor { /** * 定义拦截器:需要实现 HandlerInterceptor 接口 * * HandlerInterceptor接口中有3个方法 * 1.preHandle:在业务处理器处理请求之前被调用 * 2.postHandle:在业务处理器处理请求执行完成后,生成视图之前执行(还未渲染页面)) * 3.afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面) */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); String methodName = method.getName(); log.info("===拦截到了方法:{},在该方法执行之前执行===", methodName); // 判断用户有没有登陆,一般登陆后的用户都有一个对应的token String token = request.getParameter("token"); if (StringUtils.isEmpty(token)) { log.info("用户没有登陆,没有执行权限......请登陆"); return false; } // 通过方法,可以获取该方法上的自定义注解,然后通过注解来判断该方法是否要被拦截 // @UnInterceptor 自定义注解,不被拦截 UnInterceptor unInterceptor = method.getAnnotation(UnInterceptor.class); if (null == unInterceptor) { return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("执行完方法之后进行(Controller方法调用之后),但是此时还没有进行视图渲染"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("整个请求都处理完毕,DispatcherServlet也渲染了对应的视图,此时可以做一些清理的工作等等"); } }
)2.2 创建拦截器配置类,实现 WebMvcConfigurer 接口,对所有请求由 MyInterceptor 类进行拦截
@Configuration public class MyInterceptorConfig implements WebMvcConfigurer { /** * 解决静态资源被拦截问题 * * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { // 实现WebMvcConfigurer不会导致静态资源被拦截 registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); } }
)2.3 创建controller类,接收请求
@Controller @RequestMapping("/interceptor") public class InterceptorController { @GetMapping("/test") public String test() { return "hello"; } @UnInterceptor @GetMapping("/test1") @ResponseBody public String test1() { return "不被拦截"; } }
)2.4 创建 hello.html 页面,用于页面返回渲染
三、测试
)3.1 对于 token 校验测试。在 MyInterceptor 类中的 preHandle 方法中注释 @UnInterceptor 校验的代码,
访问 localhost:8080/interceptor/test 时,会被拦截,由于没有带token值,执行 preHandle 方法时返回false,不会继续往下执行
通过 postman 表单请求设置 token 值,再次请求
测试结果如下,可以看到 MyInterceptor 类中,三个方法都已执行,且返回了 hello.html 中的页面
)3.2 对于自定义注解校验测试。在 MyInterceptor 类中的 preHandle 方法中注释token校验的代码,放开 @UnInterceptor 的校验代码,
访问 localhost:8080/interceptor/test1 可以看到 MyInterceptor 类中,三个方法都已执行