【Spring MVC核心】拦截器Interceptor:从入门到精通,打造高可控Web层

💡 开篇故事:一次“未授权访问”引发的数据泄露

某后台管理系统因未对管理接口做权限校验,导致外部用户通过URL猜测访问到敏感数据。问题根源:权限校验逻辑分散在各个Controller中,漏掉了部分接口!直到引入全局权限拦截器,统一拦截所有请求进行身份验证,才彻底堵住漏洞。


🔍 第一章:Interceptor是谁?为何重要?

Interceptor(拦截器) 是Spring MVC框架的核心组件,用于在Controller处理请求前后视图渲染后插入自定义逻辑,实现:

  • 公共逻辑复用:如鉴权、日志、性能监控。
  • 请求流程管控:中断非法请求(如未登录用户访问)。
  • 数据预处理:参数校验、国际化设置。

核心定位:Spring MVC层的“把关者”,专注Web请求处理链路的统一控制。


🛠️ 第二章:Interceptor生命周期与核心方法

1️⃣ 生命周期
  1. preHandle:Controller方法执行前调用(可中断请求)。
  2. postHandle:Controller方法执行后,视图渲染前调用(可修改ModelAndView)。
  3. afterCompletion:视图渲染后调用(资源清理、性能统计)。
2️⃣ 核心方法详解
public class AuthInterceptor implements HandlerInterceptor {

    // 1. 预处理:返回true放行,false中断
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization");
        return isValidToken(token); // 鉴权逻辑
    }

    // 2. 后处理:可修改ModelAndView
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 
                          ModelAndView modelAndView) {
        modelAndView.addObject("timestamp", System.currentTimeMillis());
    }

    // 3. 最终处理:异常信息统计
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, 
                               Exception ex) {
        logRequestCost(request); // 记录请求耗时
    }
}

🔧 第三章:Interceptor实战——四大应用场景

1️⃣ 接口权限校验
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            // 检查方法上的注解
            if (method.hasMethodAnnotation(RequireLogin.class)) {
                return checkLogin(request);
            }
        }
        return true;
    }
}
2️⃣ 请求日志记录
public class LogInterceptor implements HandlerInterceptor {
    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        startTime.set(System.currentTimeMillis());
        log.info("Request URL: {}", request.getRequestURL());
        return true;
    }

    @Override
    public void afterCompletion(...) {
        long cost = System.currentTimeMillis() - startTime.get();
        log.info("Request cost: {}ms", cost);
        startTime.remove();
    }
}
3️⃣ 全局异常预处理
public class ExceptionInterceptor implements HandlerInterceptor {
    @Override
    public void postHandle(...) {
        if (ex != null) {
            response.setStatus(500);
            response.getWriter().write("{\"code\":500, \"msg\":\"服务异常\"}");
        }
    }
}
4️⃣ 多租户数据隔离
public class TenantInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String tenantId = request.getHeader("X-Tenant-Id");
        TenantContext.setCurrentTenant(tenantId);
        return true;
    }

    @Override
    public void afterCompletion(...) {
        TenantContext.clear();
    }
}

📊 第四章:Interceptor配置与执行顺序控制

1️⃣ 注册Interceptor(Java Config)
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/public/**");
        
        registry.addInterceptor(new LogInterceptor())
                .order(1)  // 执行顺序:数字越小优先级越高
                .addPathPatterns("/**");
    }
}
2️⃣ 执行顺序示意图

preHandle (LogInterceptor) → preHandle (AuthInterceptor) → Controller → 
postHandle (AuthInterceptor) → postHandle (LogInterceptor) → 
视图渲染 → afterCompletion (AuthInterceptor) → afterCompletion (LogInterceptor)


❗ 第五章:避坑指南 & 高频问题

1️⃣ Q:Interceptor未生效?
  • 检查点
    1. 拦截路径是否匹配(如/api/**覆盖目标接口)。
    2. 是否被excludePathPatterns排除。
    3. Spring Boot是否扫描到配置类。
2️⃣ Q:如何获取Spring管理的Bean?
  • 方案:Interceptor本身由Spring管理,可直接@Autowired注入Bean。
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Autowired
    private UserService userService;  // 直接注入
}
3️⃣ Q:Interceptor与Filter的执行顺序?
  • 执行顺序:Filter → Interceptor → Controller → Interceptor → Filter
4️⃣ Q:如何中断请求并返回JSON?
@Override
public boolean preHandle(...) {
    response.setContentType("application/json");
    response.getWriter().write("{\"code\":403, \"msg\":\"无权访问\"}");
    return false;  // 中断请求
}

🌟 第六章:最佳实践与设计原则

1️⃣ 职责单一化
  • 每个Interceptor只做一件事:如鉴权、日志、参数校验分开实现。
2️⃣ 性能优化
  • 避免阻塞操作:如远程调用应异步处理,或使用@Async。
  • 精简preHandle逻辑:快速拦截非法请求,减少资源消耗。
3️⃣ 动态配置

结合配置中心(如Nacos)动态启用/禁用拦截器:

@Autowired
private AuthInterceptor authInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
    if (config.isAuthEnabled()) {
        registry.addInterceptor(authInterceptor);
    }
}

📌 总结:Interceptor vs. Filter vs. AOP

维度InterceptorFilterAOP
作用层级Spring MVC层Servlet层业务层
访问数据可获取HandlerMethod、ModelAndView仅处理ServletRequest/Response可拦截方法调用、修改参数
依赖注入支持需借助DelegatingFilterProxy支持
适用场景Web请求预处理、后处理全局编码、跨域、安全过滤事务、日志、性能监控

黄金法则

  • Web层通用逻辑 → Interceptor
  • 底层请求/响应处理 → Filter
  • 业务层横切关注点 → AOP

📢 互动话题:你在使用Interceptor时踩过哪些坑?或者有更高阶的玩法?评论区等你分享!👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值