1. 自定义注解,需要保证幂等性的接口添加注解

      1. @Target(ElementType.METHOD)
      2. @Retention(RetentionPolicy.RUNTIME)
      3. public @interface NoRepeatSubmit {}
    2. 创建AOP切面对象,通过redis 原子操作实现。

      1. @Aspect
      2. @Component
      3. public class NoRepeatSubmitAspect {
      4. @Autowired
      5. private RedisUtils redisUtils;
      6. /** 织入点 */
      7. @Pointcut("@annotation(com.alibaba.yumao.common.annotation.NoRepeatSubmit)")
      8. public void pointCut() {}
      9. /** 环绕切 */
      10. @Around("pointCut()")
      11. public Object before(ProceedingJoinPoint pjp) {
      12. try {
      13. /** 获取上下文 */
      14. ServletRequestAttributes requestAttributes =
      15. (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
      16. HttpServletRequest request = requestAttributes.getRequest();
      17. // 从header中得到token
      18. String token = request.getHeader(BaseConstants.HTTP_HEADER_AUTH_NAME);
      19. /** 请求接口地址 */
      20. String path = request.getServletPath();
      21. // 生成key
      22. String key = RedisKeyUtils.generatorSightKey(token, path);
      23. // redis 原子操作实现幂等
      24. Boolean lockSuccess = redisUtils.setIfAbsent(key, "Y", 4);
      25. log.info("NoRepeatSubmitAspect key[{}]", key);
      26. if (lockSuccess) {
      27. log.info("NoRepeatSubmitAspect success, key[{}]", key);
      28. // 获取锁成功, 执行进程
      29. Object result = pjp.proceed();
      30. log.info("NoRepeatSubmitAspect process success, key[{}]", key);
      31. return result;
      32. }
      33. log.info("NoRepeatSubmitAspect Lock fail");
      34. return CommonResponse.buildFailMsg("请勿重复提交");
      35. } catch (Throwable throwable) {
      36. throw new BusinessException(throwable);
      37. }
      38. }
      39. }
    3. redis工具类 ```java package com.alibaba.yumao.common.utils.redis;

    import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit;

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.stereotype.Component;

    /**

    • Description:[Redis工具类]
    • 1.0.1、1.0.2支持非string类型的key、value,为了保证性能1.0.3之后只存放string类型的key、value
    • @version 1.0 */ @Component public class RedisUtils {

      /**

      • 注入redisTemplate */ private RedisTemplate redisTemplate;

        @Autowired public void setRedisTemplate(RedisTemplate redisTemplate) { RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); this.redisTemplate = redisTemplate; }

        /**

      • ‘%05d’, sequence 生成业务编号,每10小时 重置
      • @param bizKey
      • @param delta
      • @return */ public Long generateBizNum(String bizKey, long delta) { Long increment = redisTemplate.opsForValue().increment(bizKey, delta == 0 ? 5 : delta); redisTemplate.expire(bizKey, 10, TimeUnit.HOURS); return increment; }

        /**

      • 是否存在指定key *
      • @param key
      • @return */ public boolean exists(String key) { return redisTemplate.hasKey(key); }

        /**

      • set *
      • @param key
      • @param value */ public void set(String key, String value) { redisTemplate.opsForValue().set(key, value); }

        /**

      • 获取 *
      • @param key
      • @return */ public String get(String key) { return redisTemplate.opsForValue().get(key); }

        /**

      • 删除 *
      • @param key */ public void del(String key) { redisTemplate.delete(key); }

        /**

      • 设置key 过期时间,时间类型 秒 seconds *
      • @param key
      • @param value
      • @param seconds */ public void setAndExpire(String key, String value, long seconds) { redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS); }

        /**

      • 设置key 过期时间,时间类型 秒 seconds *
      • @param key
      • @param value
      • @param timeOut
      • @param timeUnit */ public void setAndExpire(String key, String value, long timeOut, TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeOut, timeUnit); }

        /**

      • 设置key 过期时间,时间类型 秒 seconds *
      • @param key
      • @param timeOut */ public void setExpire(String key, long timeOut) { redisTemplate.expire(key, timeOut, TimeUnit.SECONDS); }

        /**

      • redis hash数据类型 *
      • @param key
      • @param field
      • @param value */ public void setHash(String key, String field, String value) { redisTemplate.opsForHash().put(key, field, value); }

        /**

      • redis hash数据类型 *
      • @param key
      • @param field */ public String getHash(String key, String field) { return (String)redisTemplate.opsForHash().get(key, field); }

        /**

      • redis hash数据类型 删除 *
      • @param key
      • @param field */ public void delHash(String key, String field) { redisTemplate.opsForHash().delete(key, field); }

        /**

      • redis hash数据类型 根据key获取所有 hash key *
      • @param key */ public Set hashKeys(String key) { return redisTemplate.opsForHash().keys(key); }

        /**

      • set 设置 *
      • @param key
      • @param value */ public void setSet(String key, String value) { redisTemplate.opsForSet().add(key, value); }

        /**

      • 获取set类型的数据 *
      • @param key
      • @return */ public Set getSet(String key) { return redisTemplate.opsForSet().members(key); }

        /**

      • 数据是否存在set中 *
      • @param key
      • @param value
      • @return */ public Boolean isSetMember(String key, String value) { return redisTemplate.opsForSet().isMember(key, value); }

        /**

      • 尾部追加 *
      • @param key
      • @param value */ public void rightPush(String key, String value) { redisTemplate.opsForList().rightPush(key, value); }

        /**

      • 头部追加 *
      • @param key
      • @param value */ public void leftPush(String key, String value) { redisTemplate.opsForList().leftPush(key, value); }

        /**

      • 退栈 弹出尾部数据 *
      • @param key
      • @return */ public String rightPop(String key) { return redisTemplate.opsForList().rightPop(key); }

        /**

      • 弹栈 栈顶数据 *
      • @param key
      • @return */ public String leftPop(String key) { return redisTemplate.opsForList().leftPop(key); }

        /**

      • 获取list 数据size *
      • @param key
      • @return */ public Long getSize(String key) { return redisTemplate.opsForList().size(key); }

        /**

      • 取指定区间的数据 *
      • @param key
      • @param start
      • @param end
      • @return */ public List range(String key, long start, long end) { return redisTemplate.opsForList().range(key, start, end); }

        /**

      • 刷新redis */ public void flushDB() { redisTemplate.getConnectionFactory().getConnection().flushDb(); }

        /**

      • Description:[redis根据key自增]
      • *
      • @param key
      • @param value
      • @return java.lang.Long */ public Long increment(String key, long value) { return redisTemplate.opsForValue().increment(key, value); }

        /**

      • Description:[如果key不存在则set 并返回true,存在则不改变已经有的值 返回false] [redis setnx命令 分布式锁]
      • *
      • @param key
      • @param value
      • @return void */ public Boolean setIfAbsent(String key, String value) { return redisTemplate.opsForValue().setIfAbsent(key, value); }

        /*

      • @param key
      • 分布式锁的key
      • @param value
      • 分布式锁的值
      • @param timeoutSeconds
      • 缓存时间 单位:秒
      • @return */ public Boolean setIfAbsent(String key, String value, long timeoutSeconds) { return redisTemplate.opsForValue().setIfAbsent(key, value, timeoutSeconds, TimeUnit.SECONDS); }
      • }

        ```