spring boot 拦截器简单demo


拦截器(Interceptor)与过滤器的区别

特性 过滤器(Filter) 拦截器(Interceptor)
所属规范 Servlet 规范(javax.servlet Spring MVC 框架(基于 AOP 实现)
作用范围 所有请求(包括静态资源) 仅拦截 Controller 的请求
执行时机 在 DispatcherServlet 之前 执行 在 Controller 方法前后 执行
访问上下文 无法直接获取 Spring 的 Bean 或注解信息 可以访问 HandlerMethod(如 Controller 方法)
配置方式 通过 web.xml@WebFilter 通过 WebMvcConfigurer 注册
适用场景 全局编码、日志、安全过滤 权限校验、参数预处理、响应后处理

拦截器的核心作用

  1. 预处理:在 Controller 方法执行前进行校验或修改请求参数。
  2. 后处理:在 Controller 方法执行后修改响应数据。
  3. 完成处理:在视图渲染完成后执行资源清理操作。

拦截器的应用场景及示例代码

场景 1:接口权限验证

拦截未登录或权限不足的请求。

package com.example.spring_demo01.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !token.equals("Bearer 123456")) {
            response.setContentType("application/json");
            response.getWriter().write("{\"code\": 401, \"msg\": \"未授权访问\"}");
            return false; // 中断请求
        }
        return true; // 放行请求
    }
}

场景 2:接口耗时日志记录

记录每个接口的请求耗时。

package com.example.spring_demo01.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class LogInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        System.out.println("请求开始: " + request.getRequestURI());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        long endTime = System.currentTimeMillis();
        long startTime = (Long) request.getAttribute("startTime");
        System.out.println("请求结束,耗时: " + (endTime - startTime) + "ms");
    }
}

场景 3:接口限流

限制单个 IP 的请求频率。

package com.example.spring_demo01.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    private final ConcurrentHashMap<String, Long> ipAccessTime = new ConcurrentHashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip = request.getRemoteAddr();
        Long lastAccess = ipAccessTime.get(ip);
        long currentTime = System.currentTimeMillis();

        if (lastAccess != null && currentTime - lastAccess < TimeUnit.SECONDS.toMillis(1)) {
            response.setContentType("application/json");
            response.getWriter().write("{\"code\": 429, \"msg\": \"请求过于频繁\"}");
            return false;
        }
        ipAccessTime.put(ip, currentTime);
        return true;
    }
}

场景 4:全局参数预处理

统一处理请求参数(如去除字符串两端的空格)。

package com.example.spring_demo01.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
public class ParamTrimInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 遍历所有参数并去除空格
        request.getParameterMap().forEach((key, values) -> {
            String[] trimmedValues = new String[values.length];
            for (int i = 0; i < values.length; i++) {
                trimmedValues[i] = values[i].trim();
            }
            request.setAttribute(key, trimmedValues);
        });
        return true;
    }
}

场景 5:响应数据加密

在返回响应前对数据进行加密。

package com.example.spring_demo01.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.util.Base64;

@Component
public class ResponseEncryptInterceptor implements HandlerInterceptor {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String originalData = response.getContentType().startsWith("application/json") ? 
                (String) request.getAttribute("responseBody") : "";
        String encryptedData = Base64.getEncoder().encodeToString(originalData.getBytes());
        response.getWriter().write(encryptedData);
    }
}

注册拦截器

创建配置类实现 WebMvcConfigurer,添加拦截器并指定路径:

package com.example.spring_demo01.config;

import com.example.spring_demo01.interceptor.AuthInterceptor;
import com.example.spring_demo01.interceptor.LogInterceptor;
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 AuthInterceptor authInterceptor;

    @Autowired
    private LogInterceptor logInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 权限拦截器(拦截 /api/** 路径)
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/login"); // 排除登录接口

        // 日志拦截器(拦截所有路径)
        registry.addInterceptor(logInterceptor)
                .addPathPatterns("/**");

        // 其他拦截器...
    }
}

拦截器的执行顺序

通过 order() 方法控制拦截器执行顺序(值越小优先级越高):

registry.addInterceptor(authInterceptor)
       .order(1) // 先执行权限校验
       .addPathPatterns("/api/**");

registry.addInterceptor(logInterceptor)
       .order(2) // 后执行日志记录
       .addPathPatterns("/**");

总结

  • 拦截器优势:精准控制 Controller 方法前后的处理逻辑,适合业务相关的横切关注点。
  • 适用场景
    • 需要基于方法注解(如 @PreAuthorize)进行权限控制。
    • 需要修改请求参数或响应数据。
    • 需要记录方法级别的执行耗时。
  • 性能注意:避免在拦截器中执行耗时操作(如远程调用),以免影响接口性能。

你可能感兴趣的:(服务端,spring,boot,后端,java)