Spring boot 注解实现幂等性

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 在指定的有效期内再次发起请求时,会被拦截器识别并阻止其重复执行业务逻辑

相关推荐
LuckyLay5 分钟前
Spring学习笔记_27——@EnableLoadTimeWeaving
java·spring boot·spring
Stringzhua11 分钟前
【SpringCloud】Kafka消息中间件
spring·spring cloud·kafka
易云码15 分钟前
信息安全建设方案,网络安全等保测评方案,等保技术解决方案,等保总体实施方案(Word原件)
数据库·物联网·安全·web安全·低代码
向阳121818 分钟前
Dubbo负载均衡
java·运维·负载均衡·dubbo
newxtc20 分钟前
【客观理性深入讨论国产中间件及数据库-科创基础软件】
数据库·中间件·国产数据库·国产中间件·科创
水月梦镜花22 分钟前
redis:list列表命令和内部编码
数据库·redis·list
Gu Gu Study28 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
WaaTong1 小时前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_743048441 小时前
初识Java EE和Spring Boot
java·java-ee
AskHarries1 小时前
Java字节码增强库ByteBuddy
java·后端