Files
youlai-boot/src/main/java/com/youlai/system/aspect/DuplicateSubmitAspect.java

80 lines
2.8 KiB
Java

package com.youlai.system.aspect;
import cn.hutool.core.util.StrUtil;
import com.youlai.system.common.annotation.PreventDuplicateSubmit;
import com.youlai.system.common.result.ResultCode;
import com.youlai.system.exception.BusinessException;
import com.youlai.system.security.jwt.JwtTokenProvider;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.concurrent.TimeUnit;
/**
* 处理重复提交的切面
*
* @author haoxr
* @since 2.3.0
*/
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class DuplicateSubmitAspect {
private final RedissonClient redissonClient;
private final JwtTokenProvider jwtTokenProvider;
private static final String RESUBMIT_LOCK_PREFIX = "LOCK:RESUBMIT:";
/**
* 防重复提交切点
*/
@Pointcut("@annotation(preventDuplicateSubmit)")
public void preventDuplicateSubmitPointCut(PreventDuplicateSubmit preventDuplicateSubmit) {
log.info("定义防重复提交切点");
}
@Around("preventDuplicateSubmitPointCut(preventDuplicateSubmit)")
public Object doAround(ProceedingJoinPoint pjp, PreventDuplicateSubmit preventDuplicateSubmit) throws Throwable {
String resubmitLockKey = generateResubmitLockKey();
if (resubmitLockKey != null) {
int expire = preventDuplicateSubmit.expire(); // 防重提交锁过期时间
RLock lock = redissonClient.getLock(resubmitLockKey);
boolean lockResult = lock.tryLock(0, expire, TimeUnit.SECONDS); // 获取锁失败,直接返回 false
if (!lockResult) {
throw new BusinessException(ResultCode.REPEAT_SUBMIT_ERROR); // 抛出重复提交提示信息
}
}
return pjp.proceed();
}
/**
* 获取重复提交锁的 key
*/
private String generateResubmitLockKey() {
String resubmitLockKey = null;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = jwtTokenProvider.resolveToken(request);
if (StrUtil.isNotBlank(token)) {
String jti = (String) jwtTokenProvider.getTokenClaims(token).get("jti");
resubmitLockKey = RESUBMIT_LOCK_PREFIX + jti + ":" + request.getMethod() + "-" + request.getRequestURI();
}
return resubmitLockKey;
}
}