一、重复提交原因

由于客户端抖动,人为快速点击,造成服务器重复处理


二、后端防重复提交

1、基于token
访问请求到达服务器,服务器端生成token,分别保存在客户端和服务器。提交请求到达服务器,服务器端校验客户端带来的token与此时保存在服务器的token是否一致,如果一致,就继续操作,删除服务器的token。如果不一致,就不能继续操作,即这个请求是重复请求。

这种方案,每次提交要发送两次请求。对前端不是特别友好。

2、基于缓存

下面用缓存这种方案,技术实现:springBoot + 自定义注解 + 拦截器 + Redis缓存(分布式环境用分布式缓存Redisson);

注解RepeatSubmit

@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {/*** 防重复操作限时标记数值(存储redis限时标记数值)*/String value() default "value" ;/*** 防重复操作过期时间(借助redis实现限时控制)*/long expireSeconds() default 10;
}
@Slf4j
@Component
@Aspect
public class NoRepeatSubmitAspect {@Autowiredprivate RedisTemplate redisTemplate;/*** 定义切点*/@Pointcut("@annotation(com.ruihua.tech.master.common.ann.RepeatSubmit)")public void preventDuplication() {}@Around("preventDuplication()")public Object around(ProceedingJoinPoint joinPoint) throws Exception {/*** 获取请求信息*/ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();// 获取执行方法Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();//获取防重复提交注解RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);// 获取token以及方法标记,生成redisKey和redisValueString token = request.getHeader(IdempotentConstant.TOKEN);String url = request.getRequestURI();/***  通过前缀 + url + token + 函数参数签名 来生成redis上的 key*  没有token,换成UserId*/String redisKey = IdempotentConstant.PREVENT_DUPLICATION_PREFIX.concat(url)//.concat(token).concat(getMethodSign(method, joinPoint.getArgs()));log.info("redisKey ====== {}",redisKey);// 这个值只是为了标记,不重要String redisValue = redisKey.concat(annotation.value()).concat("submit duplication");if (!redisTemplate.hasKey(redisKey)) {// 设置防重复操作限时标记(前置通知)redisTemplate.opsForValue().set(redisKey, redisValue, annotation.expireSeconds(), TimeUnit.SECONDS);try {//正常执行方法并返回//ProceedingJoinPoint类型参数可以决定是否执行目标方法,// 且环绕通知必须要有返回值,返回值即为目标方法的返回值return joinPoint.proceed();} catch (Throwable throwable) {//确保方法执行异常实时释放限时标记(异常后置通知)redisTemplate.delete(redisKey);throw new RuntimeException(throwable);}} else {// 重复提交了抛出异常,如果是在项目中,根据具体情况处理。throw new BizException("请勿重复提交");}}/*** 生成方法标记:采用数字签名算法SHA1对方法签名字符串加签** @param method* @param args* @return*/private String getMethodSign(Method method, Object... args) {StringBuilder sb = new StringBuilder(method.toString());for (Object arg : args) {sb.append(toString(arg));}return DigestUtil.sha1Hex(sb.toString());}private String toString(Object arg) {if (Objects.isNull(arg)) {return "null";}if (arg instanceof Number) {return arg.toString();}return JSONUtil.toJsonStr(arg);}}

常量类

public interface IdempotentConstant {String TOKEN = "Authorization";String PREVENT_DUPLICATION_PREFIX = "PREVENT_DUPLICATION_PREFIX:";
}

多次点击,结果如下:

基于Java注解+AOP切面快速实现防重复提交,可胜任非高并发场景下实施应用。高并发场景下存在线程安全问题;可以使用redisson分布式锁解决;

springBoot防重复提交相关推荐

  1. springboot 防重复 提交

    转载: http://www.iocoder.cn/Spring-Boot/battcn/v2-cache-locallock/ 转载于:https://www.cnblogs.com/wanthun ...

  2. redis+aop防重复提交

    文章目录 1.防重复提交注解 2.redis分布式锁 3.防止重复提交Aop 之前有记录一篇用redis+拦截器防重复提交的内容: redis+拦截器防重复提交 1.防重复提交注解 @Target(E ...

  3. 浅谈C#在网络波动时防重复提交

    前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同).排查原因,发现是网络波动造成了重复提交. 由于网络波动而重复提交的例子也比较多: 网络上,防重复提交的方法也很多,使用redis锁, ...

  4. Spring MVC表单防重复提交

    转载自 Spring MVC表单防重复提交 利用Spring MVC的过滤器及token传递验证来实现表单防重复提交. 创建注解 @Target(ElementType.METHOD) @Retent ...

  5. 架构设计 | 接口幂等性原则,防重复提交Token管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.幂等性概念 1.幂等简介 编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.就是说,一次和多次请求某一个资源会产 ...

  6. Java的token解决方案,SpringMVC后台token防重复提交解决方案

    思路1.添加拦截器,拦截需要防重复提交的请求 2.通过注解@Token来添加token/移除token    3.前端页面表单添加(如果是Ajax请求则需要在请求的json数据中添加token值) 核 ...

  7. 处理接口超时_架构设计 | 接口幂等性原则,防重复提交Token管理

    一.幂等性概念 1.幂等简介 编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.就是说,一次和多次请求某一个资源会产生同样的作用影响. 2.HTTP请求 遵循Http协议的请 ...

  8. 表单防重复提交拦截器

    表单防重复提交 http://blog.icoolxue.com/submitted-by-spring-mvc-to-prevent-data-duplication/

  9. 关于表单防重复提交一些东东

    前阵子弄了些表单防重复提交的东西,想整理整理,免得下次要用时再四处去找,其实这里的东西还是挺简单的. 原理: 在Session中保存一个表单的唯一编号,将该编号放在一个隐藏域中,同其他数据一同提交.在 ...

最新文章

  1. phoenix php,Python实现连接phoenix的实例
  2. 随机数生成算法-二谈
  3. python当输入负数时结束_如何在lis中输入负数
  4. 给新手的 11 个 Docker 免费上手项目
  5. (转)计算几何模板 - kuangbin
  6. HALCON示例程序measure_ring.hdev齿轮齿宽度测量
  7. BestCoder Round #39 解题报告
  8. red hat linux 远程,Red Hat Linux 远程桌面 – 如何设置
  9. pb 怎么判断是 小数_考试90分以上的孩子是怎么学数学的?听听老师怎么说?
  10. Eclipse颜色主题插件-Eclipse Color Theme
  11. soundpool android,Android SoundPool:再次播放停止的声音
  12. java计算机毕业设计家庭安防系统MyBatis+系统+LW文档+源码+调试部署
  13. 毕业论文答辩技巧及注意事项(附答辩自述模板)~
  14. otl mysql 下载_OTL mySQL
  15. 阿昆同学的Java学习日记Day3
  16. 百度地图如何在html中显示图片,在网页中插入百度地图(实例)
  17. JavaScript中的Event.target
  18. OpenCV实现角点检测(cornerHarris)
  19. 永磁同步电机(PMSM)参数辨识(二)
  20. git报错error: failed to push some refs to ‘https://gitee.com/XXX/XXX-mater.git‘

热门文章

  1. MTK智能平台分区解析
  2. mtk平台androidl usb uvc camera 调试记录
  3. iphone一键转移_苹果手机如何一键转移数据 转移教程介绍
  4. python绘图黄金螺旋构图_为什么场景插画构图中要用黄金螺旋线?
  5. linux 重启内核,Linux内核文件重启
  6. 关于Unity特效未播放完的问题
  7. C语言之简单版本银行储蓄系统4(结构体版本)
  8. 程序员相亲 满屏尴尬
  9. 【项目实战】传智健康
  10. MicrobiomeAnalyst:一款综合的可视化微生物组学数据分析网页工具