拦截器 Interceptor 详解
想象一下,你正在指挥一场复杂的交响乐演出。作为指挥家,你需要在乐曲演奏过程中,精准地控制每个声部的演奏时机和节奏变化。在软件开发领域,Interceptor 就像一位经验丰富的指挥家,它能够在不改变程序原有结构的情况下,灵活地拦截程序的执行流程,并在关键节点插入额外的处理逻辑,就像指挥家在乐谱上添加一些精妙的装饰音,让程序的演奏更加优雅动听。
一、Interceptor 概念
1.1 什么是 Interceptor?
在 Web 应用中,用户的请求就像一张张乐谱,而 Controller 方法则是演奏乐曲的各个声部。Interceptor 就像一位掌控全局的指挥家,它能够拦截住用户的每一个请求,并在请求到达目标 Controller 方法之前或之后,执行一些预先安排好的动作,例如检查用户是否登录、记录请求日志、修改请求参数等等。
1.2 Interceptor 的作用
-
预处理请求 (preHandle): 就像指挥家在乐曲演奏之前,需要先确定每个声部的演奏顺序和节奏一样,Interceptor 可以在请求到达目标 Controller 方法之前,执行一些预处理逻辑,例如:
-
检查用户是否登录: 就像核对演奏者身份一样,确保只有授权用户才能访问特定资源。
-
校验请求参数: 就像检查乐器的音准一样,确保输入数据的合法性和安全性,避免出现“走调”的情况。
-
记录请求日志: 就像记录演奏时间和曲目一样,方便日后追踪问题和分析用户行为。
-
-
后处理响应 (postHandle): 如同指挥家在乐章结束后,需要对演奏效果进行点评一样,Interceptor 可以在目标 Controller 方法执行完毕后,对响应进行一些后处理操作,例如:
-
统一处理异常: 就像及时纠正演奏中的错误一样,避免将程序异常直接暴露给用户,提供更加友好的提示信息。
-
对响应数据进行加密或压缩: 就像对录音进行后期处理一样,提高数据传输效率和安全性。
-
记录响应时间: 就像统计乐曲演奏时间一样,监控系统性能,找出程序的“瓶颈”所在。
-
-
最终处理 (afterCompletion): 如同指挥家在整场演出结束后,需要对舞台进行清理和整理一样,Interceptor 可以在视图渲染完毕后,执行一些最终的清理工作,例如:
-
释放资源: 关闭数据库连接、释放文件句柄等,避免资源泄露。
-
记录最终的响应状态码和响应时间: 方便监控系统运行状况。
-
1.3 Interceptor 与 Filter 的区别
虽然 Interceptor 和 Filter 都可以拦截请求,但它们就像指挥家和舞台监督一样,负责不同的工作:
-
拦截目标不同: Filter 位于 Servlet 容器级别,就像舞台监督一样,负责管理所有演员(Servlet 和 JSP)的进出场顺序;而 Interceptor 位于 Spring MVC 框架内部,就像指挥家一样,只负责指挥演奏者(Controller)的演奏过程。
-
工作机制不同: Filter 基于回调函数机制,就像舞台监督通过广播通知演员一样;而 Interceptor 基于 Java 反射机制,就像指挥家通过指挥棒直接控制演奏者一样。
-
使用场景不同: Filter 通常用于处理与 Servlet API 相关的通用逻辑,例如设置字符编码、Gzip 压缩等,就像舞台监督负责舞台灯光和音响效果一样;而 Interceptor 更适合处理与业务逻辑相关的通用逻辑,例如权限验证、日志记录等,就像指挥家负责乐曲的艺术表现力一样,属于spring 框架提供的。
二、Spring MVC Interceptor
2.1 三大核心方法
Spring MVC Interceptor 提供了三个核心方法,就像指挥家的指挥棒一样,可以灵活地控制程序的执行流程:
-
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): 这是演奏开始前的准备工作,就像指挥家在乐章开始前,需要先确定演奏的节奏和速度一样,该方法在 Controller 方法执行之前被调用,可以用于预处理请求,例如:
-
判断用户是否登录:如果未登录,则可以重定向到登录页面,并返回 false,阻止请求继续执行;如果已登录,则返回 true,允许请求继续执行。
-
校验请求参数:如果参数不合法,则可以设置错误信息,并返回 false,阻止请求继续执行;如果参数合法,则返回 true,允许请求继续执行。
-
-
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): 这是乐章演奏后的点评环节,就像指挥家在乐章结束后,需要对演奏效果进行点评一样,该方法在 Controller 方法执行完毕后,但在视图渲染之前被调用,可以用于修改 ModelAndView 对象,例如:
-
添加模型数据:例如,可以添加一些通用的页面元素,例如网站标题、用户信息等等。
-
修改视图名称:例如,可以根据用户的角色,跳转到不同的页面。
-
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): 这是演出结束后的谢幕时间,就像指挥家在整场演出结束后,需要向观众谢幕一样,该方法在视图渲染完毕后被调用,可以用于资源清理、记录响应日志等。
简而言之:
1.preHandle方法:目标资源方法执行前执行。 返回true:放行 返回false:不放行
2.postHandle方法:目标资源方法执行后执行
3.afterCompletion方法:视图渲染完毕后执行,最后执行
2.2 代码示例
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 预处理逻辑,例如打印请求路径
System.out.println("Interceptor - preHandle: " + request.getRequestURI());
// 执行权限检查逻辑...
boolean hasPermission = checkPermission(request);
if (!hasPermission) {
// 如果没有权限,设置响应状态码为403,并返回false阻止请求继续执行
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
// 返回 true,表示放行,继续执行下一个拦截器或目标 Controller 方法
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 后处理逻辑,例如添加模型数据
System.out.println("Interceptor - postHandle");
if (modelAndView != null) {
modelAndView.addObject("message", "来自拦截器的问候!");
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 资源清理、记录响应日志等操作
System.out.println("Interceptor - afterCompletion");
}
// 模拟权限检查方法
private boolean checkPermission(HttpServletRequest request) {
// ... 检查用户是否具有访问权限 ...
return true;
}
}
2.3 配置 Interceptor
-
基于 Java 代码配置: 我们可以通过实现 WebMvcConfigurer 接口,并重写 addInterceptors() 方法来注册自定义的拦截器。
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**") // 设置拦截路径,例如拦截所有请求
.excludePathPatterns("/login", "/register"); // 设置排除路径,例如排除登录和注册请求
}
}
-
基于 XML 文件配置: 我们也可以在 Spring MVC 的配置文件中使用 <mvc:interceptors> 元素来注册自定义的拦截器。
<mvc:interceptors>
<bean class="com.example.MyInterceptor">
<property name="mappedPatterns">
<list>
<value>/**</value> <!-- 设置拦截路径 -->
</list>
</property>
<property name="excludedPatterns">
<list>
<value>/login</value> <!-- 设置排除路径 -->
<value>/register</value>
</list>
</property>
</bean>
</mvc:interceptors>
三、实战演练:Interceptor 实现登录校验
3.1 需求分析
假设我们正在开发一个电商网站,用户需要登录才能进行下单操作。为了保证网站安全,我们需要使用 Interceptor 对所有下单请求进行拦截,检查用户是否登录,如果未登录,则跳转到登录页面。
3.2 代码实现
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取用户信息
User user = (User) request.getSession().getAttribute("user");
// 判断用户是否登录
if (user == null) {
// 未登录,跳转到登录页面
response.sendRedirect("/login");
return false; // 拦截请求
}
// 已登录,放行请求
return true;
}
}
3.3 配置 Interceptor
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/order/**"); // 拦截所有以 /order/ 开头的请求
}
}
四、总结:
Interceptor 是构建灵活、可扩展 Web 应用的利器,它能够帮助我们优雅地处理横切关注点,提高代码复用性,降低系统耦合度。掌握 Interceptor 的使用,能够让我们开发出更加健壮、易于维护的 Web 应用,就像一位经验丰富的指挥家,能够指挥乐团演奏出美妙动听的乐章。
以上就是关于拦截器Interceptor的详解,希望对各位有所帮助,感谢各位看官的观看,谢谢~