Spring 中拦截器的工作流程
在Spring MVC中,拦截器(Interceptor)是一种类似于Servlet过滤器的机制,它可以拦截处理器(通常是Controller
)的请求和响应过程。拦截器通常用于实现一些通用的功能,比如认证、日志记录、请求参数处理等。Spring的拦截器是通过实现HandlerInterceptor
接口来定义的。
拦截器的主要方法
HandlerInterceptor
接口定义了三个主要的方法,分别在请求处理的不同阶段被调用:
-
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- 这个方法在请求处理之前被调用。它返回一个布尔值,如果返回
true
,表示继续执行后续的拦截器和目标方法(Controller)。如果返回false
,请求被中断,后续的拦截器和Controller不会被执行。 - 常用场景:进行身份认证、权限检查等。
- 这个方法在请求处理之前被调用。它返回一个布尔值,如果返回
-
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- 这个方法在目标方法执行之后,视图渲染之前被调用。你可以在这里对
ModelAndView
进行修改,影响视图的渲染。 - 常用场景:修改返回数据、添加通用模型数据等。
- 这个方法在目标方法执行之后,视图渲染之前被调用。你可以在这里对
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- 这个方法在请求处理完成后被调用,通常用于资源清理、记录日志或者处理异常。
- 常用场景:记录请求处理时间、清理资源、异常处理等。
拦截器的工作流程
- 请求到达:当请求到达时,
DispatcherServlet
会首先处理拦截器链。拦截器链由多个拦截器组成,它们按照配置的顺序执行。 preHandle
执行:拦截器链中的每个拦截器的preHandle
方法依次执行。如果某个拦截器的preHandle
方法返回false
,则拦截器链中止,目标方法不会被执行。- 目标方法执行:如果所有
preHandle
方法都返回true
,则执行Controller的目标方法。 postHandle
执行:在目标方法执行后,视图渲染之前,拦截器链中的每个拦截器的postHandle
方法依次执行。- 视图渲染:视图渲染完成后,Spring会调用拦截器的
afterCompletion
方法进行最后的处理。 afterCompletion
执行:所有拦截器的afterCompletion
方法依次执行,通常用于资源清理或异常处理。
实际项目中的使用示例
使用场景:用户认证
在一个典型的Spring MVC项目中,你可能需要在每个请求到达之前检查用户是否已经登录。如果未登录,重定向到登录页面;如果已登录,允许请求继续。
步骤1:定义拦截器
首先,创建一个自定义拦截器类,实现HandlerInterceptor
接口:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 检查用户是否已登录
Object user = request.getSession().getAttribute("user");
if (user == null) {
// 如果用户未登录,重定向到登录页面
response.sendRedirect("/login");
return false; // 阻止请求继续
}
return true; // 继续处理请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 可以添加一些通用数据到ModelAndView中
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 记录日志或清理资源
}
}
步骤2:注册拦截器
在Spring配置中注册这个拦截器。你可以在Java配置类中注册,也可以在XML配置文件中注册。
Java配置类方式:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/login", "/register"); // 排除登录和注册页面
}
}
步骤3:测试拦截器
当用户访问一个需要登录的页面(如/profile
)时,拦截器会检查用户是否已登录。如果未登录,用户将被重定向到登录页面。如果已登录,请求将继续执行并显示用户信息。
总结
Spring中的拦截器提供了一种非常灵活的方式来处理请求的预处理、后处理以及请求完成后的操作。通过使用拦截器,你可以在实际项目中实现如用户认证、权限控制、日志记录、异常处理等常见需求。同时,拦截器的可配置性和链式处理使得它在复杂的Web应用中非常实用。