> 文章列表 > 自定义注解--重复提交

自定义注解--重复提交

自定义注解--重复提交

文章目录

  • 前言
  • 一、实现思路
  • 二、利用aop自定义注解实现
    • 1.新增一个自定义注解
    • 2.实现自定义注解
  • 总结

前言

用于 接口防刷, 重复提交等;


一、实现思路

基于redis 的过期key 实现,一段时间内的防止重复提交

二、利用aop自定义注解实现

1.新增一个自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {boolean required() default true;
}

2.实现自定义注解

思路: 根据入参 Hash 之后转为 字符串为key,存入redis,设置失效时间,则这段时间断内再次提交,则为重复提交,直接不处理

@Aspect
@Component
@Slf4j
public class NoRepeatSubmitAspect {@Autowiredprivate StringRedisTemplate redisTemplate;@Pointcut("@annotation(com.example.test.config.NoRepeatSubmit)")public void noRepeatSubmit() {}@Around(value = "noRepeatSubmit()")public Object checkRepeatSubmit(ProceedingJoinPoint jp) throws Throwable {// 获取请求参数String paramJSON = JSONUtil.toJsonStr(jp.getArgs());// 计算请求参数hash值String hash = String.valueOf(HashUtil.fnvHash(paramJSON));// 获取到分布式锁,如果获取不到,说明重复提交,直接丢弃String value = RandomUtil.randomNumbers(10);Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(hash, value,500, TimeUnit.MILLISECONDS);if (aBoolean) {log.info("获取到锁:{}", hash);Object reuslt = jp.proceed();String lockValue = redisTemplate.opsForValue().get(hash);if (ObjectUtil.equals(lockValue,value)) {redisTemplate.delete(hash);}log.info("释放锁锁:{}", hash);return reuslt;}System.out.println("未执行");return null;}public HttpServletRequest getRequest() {RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//从获取RequestAttributes中获取HttpServletRequest的信息HttpServletRequest httpRequest = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);return httpRequest;}
}

利用redis 过期key实现
重点,重点,重点: 锁释放的时候,一定要判断,否则会将别人的锁释放,造成判断错误
当然可以继续扩展,比如根据其他 ip 用户 等,还可以根据次数进行锁定, 思路依然是 redis 过期key
第一次访问正常通过,连续点击,那么之后的请求就不会再次被处理了(甚至可以在检测到第二次为刷新的时候,延长key时间,不停刷新,不停延长,一直不处理)


总结

自定义注解写了好几篇了,都是一个套路,大家应该都学废了,不出意外,这应该是最后一个自定义注解的文章了