在 Spring 中,拦截器(Interceptor) 是一种强大的机制,用于在请求处理的不同阶段(如预处理、后处理)插入自定义逻辑。
什么是拦截器
在Spring Web MVC 中,拦截器(Interceptor)同 Servlet 中的过滤器(Filter) 类似, 都可以实现对用户的请求做出相应的处理。
所有 HandlerMapping 的实现都支持处理程序拦截器,当想将特定功能应用于某些请求时很有用 —— 例如检查权限。 拦截器必须实现
org.springframework.web.servlet 包中 HandlerInterceptor 接口的三个方法, 这些方法能够提供足够的灵活性来进行各种预处理和后处理:
- preHandle(..): Before the actual handler is run // 在实际 handler 之前运行
- postHandle(..): After the handler is run // 在 handler 之后运行
- afterCompletion(..): After the complete request has finished // 在整个请求完成后运行
preHandle 方法返回一个布尔值,可以用该方法中断或者继续执行链的处理。
- 当返回 true 时,执行链会继续执行;
- 当返回 false 时,DispatcherServlet 假定拦截器本身已经处理了请求(例如,呈现了适当的视图)并且不会继续执行其他拦截器和执行链中的实际处理程序。
【注意】:postHandle 对于 @ResponseBody 和 ResponseEntity 方法的用处不大,因为这些方法的响应是在 HandlerAdapter 中和
postHandle 之前写入和提交的。 这意味着对响应进行任何更改都为时已晚,例如添加额外的请求头。 对于此类场景,您可以实现
ResponseBodyAdvice 并将其声明为 Controller Advice bean 或直接在 RequestMappingHandlerAdapter 上进行配置。
使用方法
创建自定义拦截器类
实现 HandlerInterceptor 接口,按需重写方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor;
@Component public class CustomInterceptor implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token == null) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权"); return false; } return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("控制器处理完成"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("请求处理完毕"); } }
|
注册拦截器到 Spring MVC
通过 WebMvcConfigurer 配置类注册拦截器,并指定拦截路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import org.springframework.beans.factory.annotation.Autowired; 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 InterceptorConfig implements WebMvcConfigurer {
@Autowired private CustomInterceptor customInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(customInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login");
registry.addInterceptor(otherInterceptor); } }
|
拦截器的执行顺序
常见场景
日志拦截器
记录请求参数、耗时、响应状态;添加全局traceId
便于日志查询。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class LogInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("请求开始: " + request.getRequestURI()); request.setAttribute("startTime", System.currentTimeMillis());
String traceId = request.getHeader("traceId"); if (traceId == null) { traceId = UUID.randomUUID().toString(); }
MDC.put("traceId", traceId);
return true; }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { long startTime = (Long) request.getAttribute("startTime"); long duration = System.currentTimeMillis() - startTime; System.out.println("请求耗时: " + duration + "ms"); } }
|
注册拦截器
用于拦截非法IP调用,确保系统安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class RegisterInterceptor implements HandlerInterceptor {
@Value("${allowed.ip}") protected String allowedIp;
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { Set<String> ipSet = new HashSet<String>(Arrays.asList(allowedIp.split(",")));
String ip = WebUtil.getRequestIp(request);
if (!ipSet.contains(ip)) { System.out.println("非法IP: " + ip); return false; }
if (!(handler instanceof HandlerMethod)) { return false; }
return true;
} }
|
登录拦截器
校验用户的登录状态,比如token、session过期;以及查询用户有效性等状态信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class JWTInterceptor implements HandlerInterceptor { @Override public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
String token = request.getHeader(BaseConstant.TOKEN); if (StringUtils.isBlank(token)) { return false; }
UserToken userToken = TokenVerify.queryUser(token); if (userToken == null) { return false; }
Usee user = mapper.getUserById(userToken.getId());
if (user != null && EnumConstant.IS_NOT_VALID.getCode() == userInfoTable.getIsValid()) { return false; }
if (userInfoTable != null && EnumConstant.IS_DELETE.getCode() == userInfoTable.getIsDelete()) { return false; }
return true; } }
|
参考