1. 使用redis工具类
手动添加 RedisCache
2. 使用IP工具类
手动添加 IpUtil
3. 自定义注解
/**
* @author swt
* @date 2022/12/14 13:47
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatSubmit {
/**
* 默认1s钟以内算重复提交
* @return
*/
long timeout() default -1;
}
4. 添加切面
/**
* @author swt
* @date 2022/12/14 13:48
*/
@Aspect
@Component
public class NoRepeatSubmitAop {
@Autowired
private RedisCache redisCache;
/**
* 定义切入点
*/
@Pointcut("@annotation(NoRepeatSubmit)")
public void noRepeat() {}
/**
* 前置通知:在连接点之前执行的通知
* @param point
* @throws Throwable
*/
@Before("noRepeat()")
public ResultVO before(JoinPoint point) throws Exception{
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Assert.notNull(request, "request can not null");
// 此处可以用token或者JSessionId
//获取ip
String ip = IpUtil.getIpAddr(request);
//获取消息头中的token
String token = request.getHeader("token");
//获取请求路径
String path = request.getServletPath();
//根据请求路径+token+请求路径 组合成唯一key
String key = getKey(ip,token, path);
//这是存的value值 使用uuid统一生成唯一值
String clientId = getClientId();
//根据key获取值
Object cacheMapValue = redisCache.get(key);
// 获取注解
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
NoRepeatSubmit annotation = method.getAnnotation(NoRepeatSubmit.class);
//这是过期时间 在自定义注解中初始化
long timeout = annotation.timeout();
boolean isSuccess = false;
if (null == cacheMapValue) {
//根据key没有获取到值就重新键入一个新的值且设置过期时间
isSuccess = redisCache.set(key, clientId,timeout);
}
if (!isSuccess) {
//根据key没有获取到值就重新键入一个新的值且设置过期时间
// 获取锁失败,认为是重复提交的请求
redisCache.set(key, clientId,timeout);
throw new BusinessException("重复提交,请等待!");
}
return null;
}
private String getKey(String token, String path,String ip) {
return ip + token + ":"+path ;
}
private String getClientId() {
return UUID.randomUUID().toString();
}
}
注:redis工具类和IP工具类需要手动加入