import com.didiglobal.ehr.ehrsupport.entity.StaffInfo;
import com.didiglobal.ehr.perfservice.infrastructure.common.annotation.PreventRepeatClick;
import com.didiglobal.ehr.perfservice.infrastructure.common.constant.RedisKeyConstant;
import com.didiglobal.ehr.perfservice.infrastructure.common.exception.BusinessException;
import com.didiglobal.ehr.perfservice.infrastructure.common.exception.MsgCode;
import com.didiglobal.ehr.perfservice.infrastructure.common.util.DateTimeUtil;
import com.didiglobal.ehr.perfservice.infrastructure.common.util.RedisUtil;
import com.didiglobal.ehr.perfservice.infrastructure.common.util.UserInfoHolder;
import com.didiglobal.ehr.perfservice.infrastructure.common.util.ValueUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
@Component
@Aspect
@Slf4j
public class PreventRepeatClickAspect {
private static final String ACTION_COUNT_KEY = RedisKeyConstant.OPERATION_LOCK + "{0}-{1}";
// 防重点击事件类型
public static final String PREVENT_REPEAT_CLICK_START_CALIBRATE = "PREVENT_REPEAT_CLICK_START_CALIBRATE";
@Resource
private RedisUtil redisUtil;
@Around("@annotation(com.didiglobal.ehr.perfservice.infrastructure.common.annotation.PreventRepeatClick)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
PreventRepeatClick preventRepeatClick = method.getAnnotation(PreventRepeatClick.class);
String preventRepeatType = preventRepeatClick.preventRepeatType();
String uuid = String.valueOf(System.currentTimeMillis());
if (StringUtils.isBlank(preventRepeatType)) {
StaffInfo userInfo = UserInfoHolder.getUserInfo();
if (userInfo == null) {
log.error("can't get login user");
return joinPoint.proceed();
}
String ldap = userInfo.getLdap();
String methodName = joinPoint.getSignature().getName();
String lockKey = MessageFormat.format(ACTION_COUNT_KEY, ldap, methodName);
// 防重复提交,时间长点,因为主要是用在批量迁移的相关地方,如果执行完成,锁也会单独释放。
boolean result = redisUtil.lock(lockKey, uuid, 5 * DateTimeUtil.ONE_SECOND_PER_MILL);
if (!result) {
throw new BusinessException(MsgCode.COMMON_REPEAT_CLICK);
}
try {
return joinPoint.proceed();
} finally {
redisUtil.release(lockKey, uuid);
}
} else if (PREVENT_REPEAT_CLICK_START_CALIBRATE.equals(preventRepeatType)) { // 专门给部门开启的时候用
Map<String, Object> param = new HashMap<>();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
param.put(paramNames[i], paramValues[i]);
}
Long calibrateUnitId = (Long) param.get("calibrateUnitId");
if (ValueUtil.nullOrZero(calibrateUnitId)) {
throw new BusinessException(MsgCode.COMMON_PARAM_ERROR);
}
String lockKey = MessageFormat.format(ACTION_COUNT_KEY, PREVENT_REPEAT_CLICK_START_CALIBRATE, calibrateUnitId);
// 默认设置为3分钟 如果执行完毕 就删除锁
boolean result = redisUtil.lock(lockKey, uuid, 180 * DateTimeUtil.ONE_SECOND_PER_MILL);
if (!result) {
throw new BusinessException(MsgCode.COMMON_REPEAT_CLICK_START_CALIBRATE);
}
try {
return joinPoint.proceed();
} finally {
redisUtil.release(lockKey, uuid);
}
}
throw new BusinessException(MsgCode.COMMON_PARAM_ERROR);
}
}
// 注解类
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreventRepeatClick {
String preventRepeatType() default "";
}