当前位置: 首页 > news >正文

使用SpringBoot自定义注解+AOP+redisson锁来实现防接口幂等性重复提交

前提,整合好springboot和redis,redisson的环境

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2 编写自定义注解,注解的作用是标记一个方法是否支持防重提交

import java.lang.annotation.*;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotRepeatDuplication {/*** 延时时间 在延时多久后可以再次提交,默认10秒* @return 秒*/int delaySeconds() default 10;}

AOP切面逻辑,来判断一个方法是否被标记了该注解。如果被标记了该注解,那么就需要对该方法进行特殊处理,以实现幂等性

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;/*** 使用Redisson分布式锁来防止接口重复调用的AOP切面类*/
@Component
@Aspect
@Slf4j
public class LockMethodAOP {@Autowiredprivate RedissonClient redissonClient;/*** @param pjp:                  切入点对象,包含被拦截方法的信息* @param notRepeatDuplication: 自定义注解,用于指定防重复提交的延迟时间* @throws Throwable: 抛出异常时重新抛出* @description: 环绕通知方法,用于在方法执行前获取分布式锁,在方法执行后释放锁* @return: 执行被拦截方法的返回值*/@Around("execution(* com.example.controler..*.*(..))  && @annotation(notRepeatDuplication)  ")public Object interceptor(ProceedingJoinPoint pjp, NotRepeatDuplication notRepeatDuplication) throws Throwable {// 生成锁的唯一键String lockKey = generateKey(pjp);// 获取Redisson分布式锁RLock lock = redissonClient.getLock(lockKey);try {// 尝试获取锁,如果在指定时间内未获取到锁,则抛出异常表示重复提交boolean b = lock.tryLock(0, notRepeatDuplication.delaySeconds(), TimeUnit.SECONDS);if (!b) {throw new RuntimeException("请忽重复提交");}// 执行被拦截的方法return pjp.proceed();} catch (Throwable e) {throw new RuntimeException(e);}}/*** @param pjp: 切入点对象,包含被拦截方法的信息* @description: 生成锁的唯一键* @return: MD5加密后的字符串,用作锁的唯一键*/private String generateKey(ProceedingJoinPoint pjp) {/*** 取得类名,方法名,参数*/String className = pjp.getTarget().getClass().getName();String methodName = pjp.getSignature().getName();Object[] args = pjp.getArgs();StringBuilder sb = new StringBuilder();sb.append(className).append(":").append(methodName);for (Object arg : args) {sb.append(":").append(arg.toString());}log.info("锁的唯一键:{}",sb.toString());// 使用MD5加密生成的字符串,确保键的唯一性String s = DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8));log.info("锁的唯一键:{}",s);return s;}
}

4 测试,需要防重提交的方法,加上注解

@RestController
public class DemoController {@Autowiredprivate TBookOrderMapper tBookOrderMapper;@GetMapping("/demo")@NotRepeatDuplication(delaySeconds = 10)public String demo(@RequestBody TBookOrder tBookOrder) {// 处理请求int insert = tBookOrderMapper.insert(tBookOrder);return insert==1?"ok":"wrong";}
}


http://www.mrgr.cn/news/56350.html

相关文章:

  • Java设计模式:工厂模式详解
  • 第十八课:Python学习之多态
  • 单例设计模式(Singleton Pattern)
  • FineReport 分页
  • 【Linux】【命令】diff
  • ab命令深入解析:ApacheBench性能测试工具
  • Java避坑案例 - 消除代码重复_模板方法与工厂模式的最佳实践
  • 【10月最新】植物大战僵尸杂交版即将新增【植物】内容介绍预告(附最新版本下载链接)
  • 23种设计模式具体实现方法
  • 点云数据介绍
  • SCANeR Studio 仿真数据获取和车辆座舱数据输入
  • 强心剂!EEMD-MPE-KPCA-LSTM、EEMD-MPE-LSTM、EEMD-PE-LSTM故障识别、诊断
  • 10.22学习
  • vue中实现css布局
  • 西门子 SMART PLC 扫码串口通讯
  • 【不要离开你的舒适圈】:猛兽才希望你落单,亲人总让你回家,4个维度全面构建舒适圈矩阵
  • Shell重定向输入输出
  • 数据库表的创建
  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
  • 算法的学习笔记—数组中的逆序对(牛客JZ51)
  • 安全测试概述和用例设计
  • Modbus协议缺陷(Modbus缺陷)(一次性可读取的寄存器数量有限、不支持寄存器位级写入操作)
  • 【C++】踏上C++学习之旅(三):“我“ 与 “引用“ 的浪漫邂逅
  • 每日算法一练:剑指offer——数组篇(3)
  • IO进程_day4
  • HomeAssistant自定义组件学习-【一】