防止接口重复提交

https://www.jianshu.com/p/4c9a529ae4e9

/**
 * <p>Description: [防重复提交注解]</p >
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
   //还可以增加过期时间内的访问次数限制等  maxCount incr
    /**
     * 过期时长(毫秒)
     *
     * @return
     */
    long expire() default 500;@Aspect@Component
@Slf4j
public class NoRepeatSubmitAop {

    private static final String TOKEN_KEY = "Authorization";

    @Autowired
    private CacheService cacheService;

    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.fehorizon.erp.prepose.annotation.NoRepeatSubmit)")
    public void serviceNoRepeat() {
        // 这是一个标记方法
    }

    @Around("serviceNoRepeat()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(TOKEN_KEY);
        String url = request.getRequestURL().toString();
        String params = Arrays.toString(pjp.getArgs());
        String key =  CacheKeyBuild.buildSysAccountKey(MD5Util.MD(token + "-" + url + "-" + params));
        // 这里使用分布锁保证其线程安全(这里很关键),分布式锁实现可参考 [https://www.jianshu.com/p/d00999155166]
        String lockKey = "Lock-" + key;
        RLock lock = RedisLock.getLock(redissonClient, lockKey);采用redisson专门来做分布式锁,然后用redis做缓存服务,单纯的 put,get
     boolean res = RedisLock.lock(lock); if(!res) { throw new ServiceException(ResultCodeEnum.CODE_10007.code, ResultCodeEnum.CODE_10007.desc); } Optional<String> cacheValue = Optional.ofNullable(cacheService.getString(key)); log.info("======> " + Thread.currentThread() + "NoRepeatSubmitAop {} -> {}", key, cacheValue.isPresent()); if (!cacheValue.isPresent()) { try { Object o = pjp.proceed(); MethodSignature signature = (MethodSignature) pjp.getSignature(); NoRepeatSubmit noRepeatSubmit = signature.getMethod().getAnnotation(NoRepeatSubmit.class); // 默认500毫秒内同一认证用户同一个地址同一个参数,视为重复提交 cacheService.set(key, "0", noRepeatSubmit.expire(), TimeUnit.MILLISECONDS);//可以改造incr
          return o; }catch (ServiceException e){ log.error(e.getMessage(), e); throw e; }catch (Exception e){ log.error(ResultCodeEnum.CODE_10000.desc, e); throw new ServiceException(ResultCodeEnum.CODE_10000.code, e.getMessage()); } finally { RedisLock.unlock(lock); } } else {
        //可以增加最大次数限制的功能 RedisLock.unlock(lock);
throw new ServiceException(ResultCodeEnum.CODE_10007.code, ResultCodeEnum.CODE_10007.desc); } } }

 

posted @ 2020-08-05 15:41  brx_blog  阅读(374)  评论(0编辑  收藏  举报