SpringBoot 3.0 - 自定义注解+拦截器+Redis 解决接口幂等性
01 依赖注入
确保你的 pom.xml 文件中精准罗列以下关键依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
02 自定义注解
自定义注解 @IdempotentToken
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IdempotentToken {long expireTime() default 60; // 设置默认过期时间为 60 秒String message() default "重复请求"; // 设置默认重复请求提示信息
}
注解:
-
通过 @Target 指定注解可用范围,使其既能修饰方法又能修饰类
-
借助 @Retention 确定注解的生命周期,使其能在运行时被读取利用
-
内置可灵活配置的过期时间及提示信息参数,适配多样化业务场景需求
03 拦截器打造
拦截器 IdempotencyInterceptor,使其成为拦截请求、严谨校验幂等性 :
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;@Component
publicclassIdempotencyInterceptor implements HandlerInterceptor {@Autowiredprivate StringRedisTemplate redisTemplate;@OverridepublicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {if (handler instanceof HandlerMethod) {HandlerMethodhandlerMethod= (HandlerMethod) handler;Methodmethod= handlerMethod.getMethod();IdempotentTokenidempotentToken= method.getAnnotation(IdempotentToken.class );if (idempotentToken != null) {StringuniqueKey= generateUniqueKey(request); // 生成唯一业务标识Stringkey="idempotent:" + uniqueKey;Long expireTime= idempotentToken.expireTime();Stringvalue= redisTemplate.opsForValue().get(key);if (value == null) {redisTemplate.opsForValue().set(key, "1", expireTime, TimeUnit.SECONDS); // 初次请求,设置计数与过期时间} else {intcount= Integer .parseInt(value);if (count >= 3) {response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.getWriter().write(idempotentToken.message());returnfalse; // 阻断重复请求,返回定制化提示} else {redisTemplate.opsForValue().increment(key); // 合法请求,计数加 1}}}}returntrue;}private String generateUniqueKey(HttpServletRequest request) {// 综合用户信息、请求参数、请求路径等多维度信息生成唯一键值StringBuilderuniqueKeyBuilder=newStringBuilder();uniqueKeyBuilder.append(request.getMethod()).append(":");uniqueKeyBuilder.append(request.getRequestURI()).append(":");// 可按需追加更多细分参数,提升唯一性保障精度return uniqueKeyBuilder.toString();}
}
注解:
-
依托 Spring 的依赖注入机制,无缝整合 Redis 操作模板,为后续缓存交互提供便捷通路
-
在拦截器的核心方法 preHandle 内,精准识别标记了 @IdempotentToken 注解的方法
-
借助唯一业务标识生成策略,巧妙融合请求方法、路径等关键信息,确保每次业务操作对应独立的幂等性校验维度
-
对初次合法请求严谨设置过期时间与初始计数,对重复请求依据计数阈值果断阻断,同时返回贴合业务的定制化提示信息
04配置适配
配置类 WebConfig 中精心注册拦截器,使其全面接管系统请求的幂等性管控:
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
publicclassWebConfigimplementsWebMvcConfigurer {@Autowiredprivate IdempotencyInterceptor idempotencyInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistry registry) {registry.addInterceptor(idempotencyInterceptor).addPathPatterns("/**"); // 指定拦截器管控范围,可灵活按需细化路径匹配规则}
}
05控制器应用
业务控制器方法上轻松点缀 @IdempotentToken 注解,即刻赋予其幂等性防护能力:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/comment")
publicclassCommentController {@PostMapping("/add")@IdempotentToken(expireTime = 30, message = "短时间内评论过于频繁")public String addComment(@RequestBody CommentRequest commentRequest) {// 业务逻辑处理代码return"评论添加成功";}
}
通过以上层层递进、环环相扣的精心设计与实现,
我们成功借助 Spring Boot 3.0 的强大生态,巧妙融合自定义注解的灵活性、拦截器的管控力以及 Redis 的高效缓存特性,
为系统接口打造了一套坚固耐用、贴合实战的幂等性解决方案。