java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot拦截器怎么用

SpringBoot拦截器怎么用?从入门到实战的详细教程

作者:码农技术栈

还在为SpringMVC中的横切关注点发愁?本文用快递分拣的通俗类比,带你彻底搞懂拦截器的定位、执行流程和实战用法,从登录验证到日志记录,揭秘拦截器如何优雅处理请求,并对比过滤器差异,让你轻松掌握拦截器核心技巧

“从请求到响应的守门人——揭秘如何用拦截器优雅处理横切关注点”

一、拦截器定位图解

快递分拣中心类比解析

拦截器就像快递分拣中心的质检流程,贯穿请求处理全链路:

  1. 客户端请求:快递包裹进入分拣中心
  2. 前置处理:检查包裹是否完好(如是否有破损、地址是否清晰)
  3. 控制器处理:按地址分拣到不同区域(处理具体业务逻辑)
  4. 后置处理:再次核对分拣结果(添加物流信息)
  5. 完成处理:包裹出库前的最终检查(记录处理日志)

二、拦截器 vs 过滤器

地铁安检 vs 小区门禁对比

特性拦截器(地铁安检)过滤器(小区门禁)
管辖范围只检查进站乘客(Spring MVC 路由)检查所有进出小区的人(所有请求)
依赖关系依赖地铁系统(Spring 上下文)独立于地铁(Servlet 容器)
检查权限能查乘客包里的地铁卡(@Autowired 获取 Bean)只能看身份证(需手动获取容器)
检查时机在候车厅前后(Controller 前后)在小区大门(Servlet 前后)
典型场景检查乘客是否携带违.禁.品(登录验证)登记所有访客信息(日志记录)

三、三步实现拦截器

1. 创建拦截器类

@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    @Autowired
    private AuthService authService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 认证逻辑
        if (!authService.checkToken(request.getHeader("X-Token"))) {
            response.sendError(401, "未授权");
            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. 注册拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private AuthInterceptor authInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
            .addPathPatterns("/api/**")
            .excludePathPatterns("/api/login");
    }
}

3. 配置拦截路径

// 更精细的路径控制
registry.addInterceptor(new LogInterceptor())
    .addPathPatterns("/**")
    .excludePathPatterns("/static/**", "/error");

四、拦截器执行流程 🔄

快递包裹全流程质检图解

核心步骤详解

  1. preHandle(前置检查)
    像快递员检查包裹是否符合运输标准(如是否易燃易爆),返回 true 则继续处理,false 则直接拒绝(如未登录用户被拦截)。

  2. postHandle(后置核对)
    分拣员按地址分拣后,质检人员再次核对目的地(如订单金额计算后添加折扣信息),可修改响应内容。

  3. afterCompletion(完成处理)
    包裹出库后记录质检结果(如记录请求耗时、异常信息),即使中途出错也会执行(类似快递丢失后的追查记录)。

五、五大经典应用场景

1. 身份认证

public boolean preHandle(...) {
    String token = request.getHeader("Authorization");
    if(!jwtUtil.validateToken(token)) {
        response.sendError(401);
        return false;
    }
    return true;
}

2. 请求日志

public boolean preHandle(...) {
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    log.info("请求开始: {} {}", request.getMethod(), request.getRequestURI());
    return true;
}

public void afterCompletion(...) {
    long duration = System.currentTimeMillis() - (long)request.getAttribute("startTime");
    log.info("请求完成: 耗时{}ms", duration);
}

3. 参数预处理

public boolean preHandle(...) {
    if(request.getParameter("pageSize") == null) {
        request.setAttribute("pageSize", 10);
    }
    return true;
}

4. 响应统一包装

public void postHandle(...) {
    if(modelAndView != null) {
        modelAndView.addObject("timestamp", System.currentTimeMillis());
    }
}

5. 跨域支持

public boolean preHandle(...) {
    response.setHeader("Access-Control-Allow-Origin", "*");
    return true;
}

六、高级进阶技巧

1. 多拦截器顺序控制

registry.addInterceptor(i1).order(1);
registry.addInterceptor(i2).order(2); // 数字越小优先级越高

2. 注解驱动拦截

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuditLog {}

// 拦截器判断
if (handler instanceof HandlerMethod) {
    HandlerMethod hm = (HandlerMethod)handler;
    if (hm.hasMethodAnnotation(AuditLog.class)) {
        // 审计逻辑
    }
}

3. 异常处理

public void afterCompletion(...) {
    if(ex != null) {
        metrics.increment("error." + ex.getClass().getSimpleName());
    }
}

七、性能优化建议

  1. 轻量preHandle:前置处理尽量快速
  2. 异步处理:耗时操作放到afterCompletion
  3. 缓存验证结果:避免重复认证
  4. 合理排序:高频拦截器放前面

八、常见问题解答

Q1:拦截器能获取请求体吗?

A:可以,但需要包装Request重复读取:

ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(request);
byte[] body = wrapper.getContentAsByteArray();

Q2:如何跳过静态资源?

.excludePathPatterns("/static/**", "/favicon.ico")

Q3:拦截器vs切面怎么选?

九、Spring Boot增强配置

# 控制拦截器顺序
spring.mvc.interceptor.order=0

# 开发环境打印拦截路径
logging.level.org.springframework.web.servlet.HandlerMapping=DEBUG

十、最新趋势展望

  1. WebFlux支持:响应式拦截器
  2. GraalVM适配:原生镜像中的优化
  3. AI集成:智能路由拦截
  4. 服务网格:与Istio等方案的协同

统计显示:企业级应用中平均每个项目使用3-5个拦截器

十一、总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文