当前位置: 首页 > 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.lryc.cn/news/466995.html

相关文章:

  • k8s和ipvs、lvs、ipvsadm,iptables,底层梳理,具体是如何实现的
  • 三、归一化与标准化
  • B2105 矩阵乘法
  • centos之下的mysql8的安装
  • 计算机导论
  • 力扣209-长度最小的子数组-滑动窗口思想
  • Xilinx 7系列FPGA PCI Express IP核简介
  • 红包雨html
  • js 基础补充3
  • Invalid bean definition with name ‘employeeMapper‘ defined in file
  • 悦享驾驶,乐在旅途,首选江铃集团新能源易至EV3青春版
  • 测试WIFI和以太网的TCP带宽、UDP带宽和丢包率、延时
  • redis 第155节答疑 源码分析Hash类型ziplist结构和zlentry实体解析
  • IDE使用技巧与插件推荐
  • 1020接口测试面试题随记
  • Zotero7最新(2024)翻译问题——配置 百度API翻译
  • python程序设计员—练习笔记
  • 1.DBeaver连接hive数据库
  • CODESYS随机动态图案验证码制作详细案例(三)
  • NodeJS 使用百度翻译API
  • 摩熵数科数据产品阵容BCPM
  • ros2 .idl文件生成C、C++代码
  • scrapy的xpath在控制台可以匹配,但是到了代码无法匹配(无法匹配tbody标签)
  • OpenCL内存模型
  • Commvault Cloud如何改变网络弹性游戏规则?
  • echarts环形饼图自定义边框、标题及图例
  • Android SELinux——上下文Context源码(十)
  • 责任链模式下,解决开闭原则问题实践
  • 对Android的Binder机制的了解
  • 收藏文章_VMware17Pro虚拟机安装教程(超详细)