Spring Boot 拦截器实战:登录验证、日志记录、权限控制一网打尽!

💡 前言

在 Web 开发中,我们经常需要对请求进行统一处理,比如:

  • 判断用户是否已登录
  • 记录请求日志
  • 实现接口权限校验
  • 防止重复提交
  • 统一设置响应头信息

这些功能如果都写在每个 Controller 里,不仅代码冗余,还难以维护。而 Spring Boot 提供了强大的拦截器(Interceptor)机制,让我们可以像 AOP 一样,在请求到达 Controller 之前或之后进行统一处理。

本文将带你从零开始掌握 Spring Boot 拦截器的使用,并通过多个实用案例展示其强大之处!


🧪 一、什么是 Spring Boot 拦截器?

✅ 定义:

拦截器(HandlerInterceptor)是 Spring MVC 提供的一种用于拦截 HTTP 请求的机制。它可以在请求被 Controller 处理前后执行特定逻辑。

✅ 与 Filter 的区别:

对比项 Interceptor(拦截器) Filter(过滤器)
所属框架 Spring MVC Servlet 标准
精确度 可以精确到 Controller 方法级别 作用于所有请求
支持 Spring 注入 ✅ 支持 ❌ 不支持
执行时机 preHandle -> Controller -> postHandle -> afterCompletion doFilter

📌 适用场景:

  • 登录状态校验
  • 接口权限控制
  • 请求日志记录
  • 统一返回格式封装
  • 防止重复提交

🛠️ 二、自定义拦截器实现步骤

Step 1:创建拦截器类

实现 HandlerInterceptor 接口,并重写以下三个方法:

java 复制代码
public class LoginInterceptor implements HandlerInterceptor {

    // 请求进入 Controller 之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !token.equals("abc123")) {
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write("{\"code\":401,\"message\":\"未登录\"}");
            return false; // 中断请求
        }
        return true;
    }

    // Controller 方法执行完成后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可选操作,如添加响应头
        response.setHeader("X-Custom-Header", "interceptor-added");
    }

    // 整个请求完成(包括视图渲染)后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 可用于资源清理、日志记录等
        System.out.println("【拦截器】请求结束:" + request.getRequestURI());
    }
}

Step 2:注册拦截器

创建配置类,继承 WebMvcConfigurer 并重写 addInterceptors() 方法:

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")         // 拦截所有路径
                .excludePathPatterns("/login", "/error"); // 排除不需要拦截的路径
    }
}

🎯 三、拦截器典型应用场景实战

✅ 场景一:登录鉴权(Token 校验)

拦截所有非登录请求,判断请求头中是否携带有效 Token。

java 复制代码
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String token = request.getHeader("Authorization");
    if (token == null || !isValidToken(token)) {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        return false;
    }
    return true;
}

✅ 场景二:请求日志记录

记录每次请求的 URL、IP、耗时、参数等信息。

java 复制代码
private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    startTimeThreadLocal.set(System.currentTimeMillis());
    System.out.println("【请求开始】IP: " + request.getRemoteAddr() + ", URI: " + request.getRequestURI());
    return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    long duration = System.currentTimeMillis() - startTimeThreadLocal.get();
    System.out.println("【请求结束】耗时: " + duration + "ms");
    startTimeThreadLocal.remove();
}

✅ 场景三:接口权限控制(基于角色)

根据当前用户的角色判断是否有权限访问某个接口。

java 复制代码
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    User user = getCurrentUser(request);
    if (!user.hasPermission(request.getRequestURI())) {
        response.getWriter().write("{\"code\":403,\"message\":\"无权限\"}");
        return false;
    }
    return true;
}

✅ 场景四:防止重复提交

通过 Token 或 Redis 缓存来识别重复请求。

java 复制代码
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String token = request.getParameter("formToken");
    if (StringUtils.isEmpty(token) || RedisUtil.exists(token)) {
        response.getWriter().write("{\"code\":400,\"message\":\"请勿重复提交\"}");
        return false;
    }
    RedisUtil.set(token, "submitted", 60); // 设置有效期
    return true;
}

🧭 四、拦截器使用注意事项

注意事项 说明
拦截器顺序问题 多个拦截器按照注册顺序依次执行 preHandle,逆序执行 afterCompletion
不要阻塞主线程 如需异步处理,请使用线程池
避免频繁调用耗时操作 如数据库查询、远程调用等,可能影响性能
使用 ThreadLocal 要注意内存泄漏 每次请求结束后记得 remove 清理
不建议替代 Filter 如跨域、编码处理等仍推荐使用 Filter

📘 五、总结对比表

功能 说明
preHandle 在 Controller 执行前调用,可中断请求
postHandle 在 Controller 执行后、视图渲染前调用
afterCompletion 请求完全结束后调用,可用于资源释放
应用场景 登录校验、权限控制、日志记录、防重提交
优点 解耦业务逻辑、统一处理请求
缺点 滥用会影响性能、增加系统复杂度

🎁 六、结语

Spring Boot 拦截器是构建高质量 Web 应用不可或缺的利器之一。通过合理使用拦截器,我们可以优雅地实现登录验证、权限控制、日志记录等通用功能,使代码更简洁、系统更健壮。

无论你是开发企业级后台管理系统,还是搭建高并发 API 接口平台,都应该掌握拦截器的使用技巧。


🎯 点赞、收藏、转发本文,让更多开发者受益!

相关推荐
用户908324602731 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840822 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解2 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解2 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记2 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者3 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840823 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解3 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者4 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺4 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端