1. 添加 Spring AOP 依赖
在 pom.xml 中添加如下依赖:
XML
<dependencies>
<!-- Spring AOP dependency -->
<dependency>
<groupIdorg.springframework.boot</groupId>
<artifactIdspring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
2. 创建自定义幂等性注解
创建一个新的 Java 注解类,通过 @interface 关键字来定义,并可以添加元注解以及属性。
java
/**
* 《像乌鸦一样思考》让孩子学会观察和独立思考!
* https://www.sanzhiwa.top/6718.html
*/
@Retention(RetentionPolicy.RUNTIME) // 程序运行时有效
@Target(ElementType.METHOD) // 方法注解
public @interface Idempotent {
/**
* 请求标识符的参数名称,默认为"requestId"
*/
String requestId() default "requestId";
/**
* 幂等有效时长(单位:秒)
*/
int expireTime() default 60;
}
3. 创建拦截器
java
/**
* 清华附小1-6年级趣味英语动画
* https://www.sanzhiwa.top/6711.html
*/
@Component
public class IdempotentInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Method method = ((HandlerMethod) handler).getMethod();
Idempotent idempotent = method.getAnnotation(Idempotent.class);
if (idempotent != null) {
// 获取请求中的唯一标识符
String requestId = obtainRequestId(request, idempotent.requestId());
// 判断该请求是否已经处理过
if (redisTemplate.opsForValue().get(idempotentKey(requestId)) != null) {
// 已经处理过,返回幂等响应
response.getWriter().write("重复请求");
return false;
} else {
// 将请求标识符存入Redis,并设置过期时间
redisTemplate.opsForValue().set(idempotentKey(requestId), "processed", idempotent.expireTime(), TimeUnit.SECONDS);
return true; // 继续执行业务逻辑
}
}
return super.preHandle(request, response, handler);
}
private String idempotentKey(String requestId) {
return "idempotent:" + requestId;
}
private String obtainRequestId(HttpServletRequest request, String paramName) {
// 实现从请求中获取唯一标识符的方法
return request.getParameter(paramName);
}
}
4. 配置拦截器
在 Spring Boot 配置文件类中,添加拦截器配置:
java
/**
* 儿童新概念英语
* https://www.sanzhiwa.top/6696.html
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private IdempotentInterceptor idempotentInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(idempotentInterceptor)
.addPathPatterns("/**"); // 拦截所有接口
}
}
5.使用自定义注解
最后,在需要进行幂等控制的 Controller 方法上使用 @Idempotent 注解:
java
/**
*
* 微观小世界】奇趣探险,启程进入神秘的微观世界!
* https://www.sanzhiwa.top/6704.html
*/
@RestController
public class TestController {
@PostMapping("/order")
@Idempotent(requestId = "orderId") // 假设orderId是从客户端传来的唯一标识订单请求的参数
public String placeOrder(@RequestParam("orderId") String orderId, ...) {
// 业务处理逻辑
}
}
这样,当有相同的请求 ID 在指定的有效期内再次发起请求时,会被拦截器识别并阻止其重复执行业务逻辑