目录
拦截器概述
拦截器的工作原理
拦截器的使用步骤
拦截器接口方法解释
场景示例
1. 创建拦截器类
2. 配置拦截器
3. 创建控制器
4. 测试拦截器
其他常见场景
在 Spring MVC 中,拦截器(Interceptor)是一种可以在请求处理的不同阶段进行预处理和后处理的组件。它类似于 Servlet 中的过滤器(Filter),但拦截器是 Spring MVC 框架特有的,主要用于对控制器方法的调用进行拦截和处理。拦截器可以在请求到达控制器之前、控制器方法执行之后以及视图渲染完成之后执行特定的逻辑,从而实现诸如权限验证、日志记录、性能监控等功能。
Spring MVC 的拦截器基于 Java 的反射机制和 AOP(面向切面编程)思想实现。当一个请求进入 Spring MVC 框架时,DispatcherServlet
会根据配置的拦截器链,依次调用拦截器的预处理方法。如果所有拦截器的预处理方法都返回 true
,则请求会继续传递到控制器的处理方法;如果某个拦截器的预处理方法返回 false
,则请求将被拦截,后续的拦截器和控制器方法都不会执行。在控制器方法执行完成后,拦截器的后处理方法会被依次调用,最后在视图渲染完成后,拦截器的完成处理方法会被调用。
HandlerInterceptor
接口或继承 HandlerInterceptorAdapter
类(HandlerInterceptorAdapter
是 HandlerInterceptor
的一个抽象实现类,在 Spring 5.3 及以后版本已被弃用),重写其中的方法。HandlerInterceptor
接口定义了三个方法:
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
:在控制器方法执行之前被调用。如果返回 true
,则继续执行后续的拦截器和控制器方法;如果返回 false
,则请求处理流程终止,后续的拦截器和控制器方法都不会执行。可以在该方法中进行权限验证、日志记录等操作。postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
:在控制器方法执行之后、视图渲染之前被调用。可以在该方法中对 ModelAndView
对象进行修改,如添加额外的模型数据。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
:在视图渲染完成之后被调用。无论请求处理过程中是否发生异常,该方法都会被执行。可以在该方法中进行资源清理、日志记录等操作。import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre-handle method is called. Request URL: " + request.getRequestURL());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Post-handle method is called.");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("After-completion method is called.");
}
}
在上述代码中,LoggingInterceptor
类实现了 HandlerInterceptor
接口,并重写了三个方法。preHandle
方法在请求处理前打印请求的 URL,postHandle
方法在控制器方法执行后打印信息,afterCompletion
方法在视图渲染完成后打印信息。
如果使用 Java 配置,可以通过实现 WebMvcConfigurer
接口来配置拦截器:
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 LoggingInterceptor())
.addPathPatterns("/**"); // 拦截所有请求
}
}
在上述代码中,WebConfig
类实现了 WebMvcConfigurer
接口,重写了 addInterceptors
方法,将 LoggingInterceptor
拦截器注册到拦截器链中,并指定拦截所有请求(addPathPatterns("/**")
)。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@GetMapping("/hello")
@ResponseBody
public String sayHello() {
return "Hello, World!";
}
}
在上述代码中,HelloController
类包含一个处理 /hello
请求的方法,返回一个简单的字符串。
当访问 http://localhost:8080/hello
时,控制台会输出以下信息:
Pre-handle method is called. Request URL: http://localhost:8080/hello
Post-handle method is called.
After-completion method is called.
这表明拦截器的三个方法按顺序被调用,实现了对请求处理过程的拦截和日志记录。
preHandle
方法中检查用户是否具有访问某个资源的权限,如果没有则返回 false
并跳转到登录页面。import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
if (session.getAttribute("user") == null) {
response.sendRedirect("/login");
return false;
}
return true;
}
}
preHandle
方法中记录请求开始时间,在 afterCompletion
方法中记录请求结束时间,计算请求处理时间。import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class PerformanceInterceptor implements HandlerInterceptor {
private ThreadLocal startTime = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
startTime.set(System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime.get();
System.out.println("Request URL: " + request.getRequestURL() + ", Execution time: " + executionTime + " ms");
startTime.remove();
}
}
通过使用拦截器,可以在不修改控制器代码的情况下,对请求处理过程进行增强和扩展,提高代码的可维护性和复用性。