SpringBoot实现表单重复提交检测
【摘要】 前言在实际开发过程中,web应用经常会出现网络延迟,接口处理时间略长,用户习惯等原因造成的客户连续多次点击提交按钮调用接口,导致数据库会出现重复数据或这接口业务逻辑bug等问题 方案利用redis锁实同一个用户同一个请求2秒内重复提交返回错误路由 SubmitLock标记需要拦截的方法@Target({ElementType.METHOD})@Retention(RetentionPoli...
前言
在实际开发过程中,web应用经常会出现网络延迟,接口处理时间略长,用户习惯等原因造成的客户连续多次点击提交按钮调用接口,导致数据库会出现重复数据或这接口业务逻辑bug等问题
方案
利用redis锁实同一个用户同一个请求2秒内重复提交返回错误路由
SubmitLock
标记需要拦截的方法
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SubmitLock {
int expire() default 2;
}
RedisLockUtil
redis锁校验及写入
@Component
public class RedisLockUtil {
@Autowired
private RedisUtil redisUtil;
private int lockDBIndex = 1;
public boolean lock(String key,String clientID,int lockExpire){
if(redisUtil.isValid(key,lockDBIndex)){
return false;
}else{
redisUtil.redisTemplateSet(key,clientID,lockDBIndex);
redisUtil.setExpire(key,lockExpire, TimeUnit.SECONDS,lockDBIndex);
return true;
}
}
}
RepeatSubmitAspect
统一拦截切面
@Aspect
@Component
@Order(value = 100)
public class RepeatSubmitAspect {
private static Logger logger = LoggerFactory.getLogger(RepeatSubmitAspect.class);
@Autowired
private RedisLockUtil redisLockUtil;
/**
* 切面点 指定注解
*/
@Pointcut("@annotation(com.haopan.frame.common.annotation.SubmitLock) " +
"|| @within(com.haopan.frame.common.annotation.SubmitLock)")
public void repeatSubmitAspect() {
}
/**
* 拦截方法指定为 repeatSubmitAspect
*/
@Around("repeatSubmitAspect()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
SubmitLock submitLock = method.getAnnotation(SubmitLock.class);
if (submitLock != null) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("token");
if (!StringUtil.isEmpty(token)) {
String path = request.getServletPath();
String key = "submitLock|" + token + "|" + path;
String clientId = CommonUtil.getNewGuid();
if (redisLockUtil.lock(key, clientId, submitLock.expire())) {
// 获取锁成功
return point.proceed();
} else {
System.out.println("tryLock fail, key = ["+key+"]");
return Result.errorResult().setMsg("重复请求,请稍后再试").setCode(-980);
}
} else {
return point.proceed();
}
} else {
return point.proceed();
}
}
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)