Interceptor 介绍 **拦截器(Interceptor)**同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。
你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置……
在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。
Spring Interceptor是一个非常类似于Servlet Filter 的概念 。
Interceptor 作用
- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
- 权限检查:如登录检测,进入处理器检测是否登录;
- 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
- 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor { /**
* This implementation always returns {@code true}.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {return true;
} /**
* This implementation is empty.
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
} /**
* This implementation is empty.
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
} /**
* This implementation is empty.
*/
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
}}
- preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是 Boolean 类型,当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。
- postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。
- afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。
LogInterceptor 类:
public class LogInterceptor extends HandlerInterceptorAdapter {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("
-------- LogInterception.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Start Time: " + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
return true;
}@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("
-------- LogInterception.postHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("
-------- LogInterception.afterCompletion --- ");
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("End Time: " + endTime);
System.out.println("Time Taken: " + (endTime - startTime));
}
}
OldLoginInterceptor 类:
public class OldLoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("
-------- OldLoginInterceptor.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login");
response.sendRedirect(request.getContextPath()+ "/admin/login");
return false;
}@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("
-------- OldLoginInterceptor.postHandle --- ");
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("
-------- OldLoginInterceptor.afterCompletion --- ");
}}
配置拦截器 :
@Configurationpublic
class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin");
registry.addInterceptor(new AdminInterceptor()).addPathPatterns("/admin/*").excludePathPatterns("/admin/oldLogin");
}
}
LogInterceptor 拦截器用于拦截所有请求; OldLoginInterceptor 用来拦截链接 “ / admin / oldLogin”,它将重定向到新的 “ / admin / login”。;AdminInterceptor用来拦截链接 “/admin/*”,除了链接 “ / admin/oldLogin”。
自定义 Controller 验证拦截器
@Controllerpublic
class LoginController {
@RequestMapping("/index")
public String index(Model model){
return "index";
} @RequestMapping(value = "https://www.it610.com/admin/login")
public String login(Model model){
return "login";
}
}
拦截器顺序 spring中拦截器执行顺序: 多个拦截器顺序:
- 默认的注册顺序
- InterceptorRegistry#order(int)方法指定顺序,值越小优先级越高
public class PathInterceptor implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("PathInterceptor 执行");
System.out.println("第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、");
return true;
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("PathInterceptor afterCompletion 完成");
}
}
拦截器2
public class TestInterceptor implements HandlerInterceptor {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("TestInterceptor 执行");
System.out.println("第二个执行的拦截器。巴拉巴拉、、、、");
return true;
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("TestInterceptorafterCompletion 完成");
}
}
【面试|Spring Boot拦截器(Interceptor)详解】默认情况下,拦截器按照注册的顺序执行:
@Bean
public TestInterceptor testInterceptor() {
return new TestInterceptor();
}@Bean
public PathInterceptor pathInterceptor() {
return new PathInterceptor();
}@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor()).addPathPatterns("/**");
registry.addInterceptor(pathInterceptor()).addPathPatterns("/**");
}
输出:
TestInterceptor 执行
第二个执行的拦截器。巴拉巴拉、、、、
PathInterceptor 执行
第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、
PathInterceptor afterCompletion 完成
TestInterceptorafterCompletion 完成
通过面向百度编程发现
- 可以使用 @Order 注解定义顺序
- 实现Ordered接口
测试发现都不生效,注解无论放到拦截器类上还是放到@Bean注解的位置都无效
注册拦截器时,使用 InterceptorRegistry#order(int) 方法指定顺序,值越小优先级越高。
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor()).addPathPatterns("/**").order(2);
registry.addInterceptor(pathInterceptor()).addPathPatterns("/**").order(1);
}
输出:
PathInterceptor 执行
第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、
TestInterceptor 执行
第二个执行的拦截器。巴拉巴拉、、、、
TestInterceptorafterCompletion 完成
PathInterceptor afterCompletion 完成
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
推荐阅读
- 面试|Spring Boot报错 org.springframework.jdbc.BadSqlGrammarException
- 面试|Spring Boot框架
- 面试|解决——》Handler dispatch failed; nested exception is java.lang.NoSuchMethodError
- WebGL管网展示(及TubeGeometry优化)
- js获取git分支信息
- Visual|VSCode中Vue3插件使用整理_Vue3开发插件
- #|vue使用 APlayer+Meting实现音乐播放,支持多平台音乐(网易云、腾讯、虾米、酷狗、百度)
- 笔记|如何在若依中做数据权限
- Web|Web学习(十一) Vue