业务背景:后端实现前端防止重复提交
常规思路:自定义一个注解,在需要用到的注解的方法上加上即可,aop会自动扫描该注解并执行切面逻辑
1.自定义注解代码如下:
2.定义切面逻辑如下:
@Resource
private RedissonClient redissonClient;
/**
* 防止表单重复提交
* @param joinPoint 切入点
* @return
*/
@Around("@annotation(NoRepeat)")
public Object aroundUnRepeat(ProceedingJoinPoint joinPoint) throws Throwable {
//获取token
String token = WebUtils.getToken(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
if(StringUtils.isEmpty(token)){
return joinPoint.proceed();
}
//解析方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String className = joinPoint.getTarget().getClass().getName();
String methodName = method.getName();
Object result = null;
//获取分布式锁 lock+redissession
RLock lock = redissonClient.getLock(buildKey(className, methodName, token));
if(lock.isLocked()){
//如果已经被锁,则网络繁忙,要求用户重新刷新
throw new BaseRuntimeException(CommonResultCode.NETWORK_BUSY);
}
try {
lock.tryLock(1,1, TimeUnit.SECONDS);
result = joinPoint.proceed();
} finally {
if(lock.isLocked()){
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
return result;
}
/**
* 防止重复提交的key com.hkbt.test.Test:test:jslfignsowetn
* @param fullClassName
* @param methodName
* @param token
* @return
*/
private String buildKey(String fullClassName,String methodName,String token){
return fullClassName + AnnoConstant._M + methodName + AnnoConstant._M + token;
}