自定义注解,需要保证幂等性的接口添加注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {}
创建AOP切面对象,通过redis 原子操作实现。
@Aspect
@Component
public class NoRepeatSubmitAspect {
@Autowired
private RedisUtils redisUtils;
/** 织入点 */
@Pointcut("@annotation(com.alibaba.yumao.common.annotation.NoRepeatSubmit)")
public void pointCut() {}
/** 环绕切 */
@Around("pointCut()")
public Object before(ProceedingJoinPoint pjp) {
try {
/** 获取上下文 */
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 从header中得到token
String token = request.getHeader(BaseConstants.HTTP_HEADER_AUTH_NAME);
/** 请求接口地址 */
String path = request.getServletPath();
// 生成key
String key = RedisKeyUtils.generatorSightKey(token, path);
// redis 原子操作实现幂等
Boolean lockSuccess = redisUtils.setIfAbsent(key, "Y", 4);
log.info("NoRepeatSubmitAspect key[{}]", key);
if (lockSuccess) {
log.info("NoRepeatSubmitAspect success, key[{}]", key);
// 获取锁成功, 执行进程
Object result = pjp.proceed();
log.info("NoRepeatSubmitAspect process success, key[{}]", key);
return result;
}
log.info("NoRepeatSubmitAspect Lock fail");
return CommonResponse.buildFailMsg("请勿重复提交");
} catch (Throwable throwable) {
throw new BusinessException(throwable);
}
}
}
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