注解
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmitAnno {
/**
* 锁定时间
* @return 锁定时间,默认是3 TimeUnit 默认是秒
*/
long lockedTime() default 3;
/**
* 时间单位(时分秒等)
* @return 单位
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
AOP
/**
* 防重复提交切面类
*
* @author xy
* @date 2024-06-05
*/
@Aspect
@Component
public class RepeatSubmitAspect {
private Logger logger = LoggerFactory.getLogger(RepeatSubmitAspect.class);
@Resource
private RedisUtil redisUtil;
/**
* 切入点定义:指明要在什么样的条件下才能被触发
*
* @ Pointcut注解表达式, 通过特定的规则来筛选连接点, 就是Pointcut,选中那几个你想要的方法
* @ annotation:条件:当执行的方法上拥有指定的注解时生效
*/
@Pointcut("@annotation(com.zqcy.commons.anno.RepeatSubmitAnno)")
public void pointCut() {
}
/**
* 环绕通知,围绕着方法执行
*
* @ param pjp
* @ return
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint pjp) {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert attributes != null;
MethodSignature signature = (MethodSignature) pjp.getSignature();
// 被拦截的方法
Method method = signature.getMethod();
// 注解信息
RepeatSubmitAnno repeatSubmit = method.getAnnotation(RepeatSubmitAnno.class);
HttpServletRequest request = attributes.getRequest();
String key = "repeat_submit_";
String url = request.getRequestURI();
String ipAddress = request.getRemoteAddr();
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
//基于IP 类名 方法名 和URL 生成唯一key
key = key + String.format("%s_%s_%s_%s", ipAddress, url, className, methodName);
// 如果缓存中有这个url视为重复提交
if (!redisUtil.hasKey(key) ) {
Object o = pjp.proceed();
redisUtil.setCacheSet(key,"",repeatSubmit.lockedTime(),repeatSubmit.timeUnit());
return o;
} else {
// logger.error("重复提交");
return "请勿短时间内重复操作" ;
}
} catch (Throwable e) {
// e.printStackTrace();
logger.error("验证重复提交时出现未知异常!");
return "验证重复提交时出现未知异常!";
}
}
}
使用 :在需要的方法上添加
@RepeatSubmitAnno(lockedTime = 500,timeUnit = TimeUnit.MILLISECONDS)