1.前端处理(场景:用于网络延迟情况下用户点击多次submit按钮导致表单重复提交)

①:通过一个标识来控制表单提交之后,再次提交会直接返回处理。

Var isCommitted = false;  //表单是否应提交标识,默认为false
function dosubmit() {//start hzjIf(isCommitted == false){//提交表单后,将表单是否已经提交设置为trueisCommitted = true;//返回true让表单正常提交return true;}else{return false; //返回false表单不提交}//end hzj}

**总结:**将以上的判断逻辑加在提交业务之前和业务处理之后都可以

②:通过点击提交一次按钮之后,将该按钮设置为不可用处理。

function dosubmit() {//获取表单提交按钮Var btnSubmit = documen.getElementById(“sumit”);//将表单提交按钮设置为不可用,可以避免用户再次点击提交按钮进行提交btnSubmit.disabled = “disabled”;//返回true让表单可以提交return true;}

**总结:**将这个方法放到第一次提交按钮成功之后,会将按钮设置为不可点击状态。

2.后端处理(场景1:表单提交后,用户点击-刷新-按钮导致表单重复提交。场景2:用户表单提交后,点击浏览器的-后退-按钮,退到表单提交页面,再次提交按钮导致表单重复提交。)

①:给数据库增加唯一键约束(简单粗暴)

在数据库建表的时候在ID字段添加主键约束,用户名、邮箱、电话等字段加唯一性约束。确保数据库只可以添加一条数据。
数据库加唯一性约束sql:
alter table tableName_xxx add unique key uniq_xxx(field1, field2)
服务器及时捕捉插入数据异常:try {xxxMapper.insert(user);} catch (DuplicateKeyException e) {logger.error("user already exist");}

**总结:**针对给表中字段新增入库的情况

②:session技术实现
a.在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。
b.然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。
c.然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。

//1.登录controller层String token = TokenProccessor.getInstance().makeToken();//创建令牌request.getSession().setAttribute("token", token);  //在服务器使用session保存token(令牌)return data;//返回成功数据,跳转到坐席端首页页面(将token放入data中,返回页面将token放入隐藏域中的表单标签中)
//2.前端页面表单中放入token
<input type="hidden" name="token" value="token值"/>
//3.正真处理提交业务的逻辑层
boolean b = isRepeatSubmit(request);//判断用户是否是重复提交if(b==true){System.out.println("请不要重复提交");return;}request.getSession().removeAttribute("token");//移除session中的tokenSystem.out.println("处理用户提交请求!!");}/*** 判断客户端提交上来的令牌和服务器端生成的令牌是否一致* @param request* @return *         true 用户重复提交了表单 *         false 用户没有重复提交表单*/private boolean isRepeatSubmit(HttpServletRequest request) {String client_token = request.getParameter("token");//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单if(client_token==null){return true;}//取出存储在Session中的tokenString server_token = (String) request.getSession().getAttribute("token");//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单if(server_token==null){return true;}//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单if(!client_token.equals(server_token)){return true;}return false;}
//4.生成token的工具类
public class TokenProccessor {/**单例设计模式(保证类的对象在内存中只有一个)*1、把类的构造函数私有*2、自己创建一个类的对象*3、对外提供一个公共的方法,返回类的对象*/private TokenProccessor(){}private static final TokenProccessor instance = new TokenProccessor();/*** 返回类的对象* @return*/public static TokenProccessor getInstance(){return instance;}/*** 生成Token* Token:Nv6RRuGEVvmGjB+jimI/gw==* @return*/public String makeToken(){  //checkException//  7346734837483  834u938493493849384  43434384String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";//数据指纹   128位长   16个字节  md5try {MessageDigest md = MessageDigest.getInstance("md5");byte md5[] =  md.digest(token.getBytes());//base64编码--任意二进制编码明文字符   adfsdfsdfsfBASE64Encoder encoder = new BASE64Encoder();return encoder.encode(md5);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}}

**总结:**使用session技术,是一个用户对应一个session容器

③:使用AOP自定义切入实现
1.自定义防止重复提交标记(@AvoidRepeatableCommit)。
2.对需要防止重复提交的Congtroller里的mapping方法加上该注解。
3.新增Aspect切入点,为@AvoidRepeatableCommit加入切入点。
4.每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
5.重复提交时Aspect会判断当前redis是否有该key,若有则拦截。

//首先自定义注解
/*** 避免重复提交* @author * @version* @since*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidRepeatableCommit {/*** 指定时间内不可重复提交,单位毫秒,默认10000毫秒*/long timeout()  default 10000 ;
}
//创建切面类
/*** 重复提交aop*/
@Aspect//
@Component
public class AvoidRepeatableCommitAspect {private static final Logger logger = Logger.getLogger(AvoidRepeatableCommitAspect.class);@SuppressWarnings("rawtypes")@Autowiredprivate RedisTemplate redisTemplate;/** * @param point 连接点*/@SuppressWarnings("unchecked")@Around("@annotation(com.***.annotation.AvoidRepeatableCommit)")//切面拦截public Object around(ProceedingJoinPoint point) throws Throwable {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String ip = IPUtil.getIP(request);//此处method获取的是代理对象(由代理模式生成的)的方法MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();//此处realMethod是目标对象(原始的)的方法// Method realMethod = point.getTarget().getClass().getDeclaredMethod(signature.getName(),method.getParameterTypes()); //目标类、方法String className = method.getDeclaringClass().getName();String name = method.getName();String ipKey = String.format("%s#%s",className,name);int hashCode = Math.abs(ipKey.hashCode());String key = String.format("%s_%d",ip,hashCode);//logger.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);logger.info(String.format("ipKey={},hashCode={},key={}",ipKey,hashCode,key));//通过反射技术来获取注解对象AvoidRepeatableCommit avoidRepeatableCommit =  method.getAnnotation(AvoidRepeatableCommit.class);long timeout = avoidRepeatableCommit.timeout();if (timeout < 0){//过期时间10秒timeout = 10000;}//获取key键对应的值String value = (String) redisTemplate.opsForValue().get(key);if (StringUtils.isNotBlank(value)){return new Message(1,"请勿重复提交!");}//新增一个字符串类型的值,key是键,value是值。redisTemplate.opsForValue().set(key, UUIDUtil.uuid(),timeout,TimeUnit.MILLISECONDS);//返回继续执行被拦截到的方法    return point.proceed();}}

注意:
这个类有两个注释,分别是@Component和@Aspect,
@Component是使得AvoidRepeatableCommitAspect 受Spring托管并实例化。
@Aspect就是使得这个类具有AOP功能(你可以这样理解)两个注解缺一不可
类里面只有一个方法,名字叫做around,其实就是为了防重复提交的!

//在我需要防重复提交的方法上添加 自定义注解
// 新增@AvoidRepeatableCommit //自定义注解@RequestMapping(method = RequestMethod.POST)public @ResponseBody Message create(SourceEntity sourceEntity) {//设置创建时间sourceEntity.setGmt_create(new Date());//保存数据库sourceEntity.save(sourceEntity);return MessageUtil.message("sourceEntity.create.success");}

**总结:**到这里就完成了,主要步骤就是通过每次提交表单时,Aspect都会保存当前key到reids(先设置过期时间)。重复提交时Aspect会判断当前redis是否有该key,若有则拦截。没有就放行。

防止表单重复提交几种方法+实测相关推荐

  1. 表单重复提交的解决方法

    表单重复提交的解决方法 参考文章: (1)表单重复提交的解决方法 (2)https://www.cnblogs.com/lwj-0923/p/7367517.html 备忘一下.

  2. html怎么防止表单重复提交,js防止表单重复提交的解决方法

    防止表单重复提交,通常会通过attachEvent在 form的onsubmit事件中写一个方法,每次触发该事件时执行该方法,可以给form增加一个submited属性,每次判断这个属性,为 fals ...

  3. 防止表单重复提交的实现方法!

    我们做添加信息页面的时候经常会遇到这样的问题,用户有时候会重复的点击提交按钮(实际上测试人员经常这样干),会导致多次提交,产生重复数据,我们总是要写一段代码要在表单提交后把提交按钮设置disibled ...

  4. 【重复提交表单】表单重复提交的三种情况,解决办法

    引入 看一个重复提交表单的例子 F12可以看到,请求体中的参数在刷新页面之后仍然保留,因此每一次刷新页面,都会把现有的请求体中的表单数据提交一次到服务器,而接收的页面还是insert.jsp,于是造成 ...

  5. 5位随机数重复的概率 php_php防止表单重复提交的方法

    Token,就是令牌,最大的特点就是随机性,不可预测. Token一般用在两个地方--防止表单重复提交.anti csrf攻击(跨站点请求伪造). 两者在原理上都是通过session token来实现 ...

  6. python表单防重复提交_关于PHP使用token防止表单重复提交的方法

    这篇文章主要介绍了PHP使用token防止表单重复提交的方法,通过生成一个加密后的随机数存入session的token变量,同时将该值放入表单隐藏提交,达到防止表单重复提交的功能,需要的朋友可以参考下 ...

  7. php token 表单重复提交,PHP生成token防止表单重复提交2个例子

    防止表单重复提交的解决方案非常的简单,我们下面两个例子都是生成一个随机的token验证用户是不是由我们站内提交并且进行重复验证即可实现了. 在网上搜索了一下有很多站长都这样说的 1.提交按钮置disa ...

  8. 防止表单重复提交的4种方法

    1.背景与介绍: 平时开发的项目中可能会出现下面这些情况: 由于用户误操作,多次点击表单提交按钮. 由于网速等原因造成页面卡顿,用户重复刷新提交页面. 黑客或恶意用户使用postman等工具重复恶意提 ...

  9. 后台防止表单重复提交的三种方法

    方案一:利用Session防止表单重复提交 具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送 ...

最新文章

  1. 请教开发WinForm时输入法问题
  2. OpenCV捕获格雷码模式
  3. php接收文件,如何通过php 发送与接收流文件
  4. Android拍照上传代码样例
  5. string转int/float/double、int/float/double转string、转字符串数组的方法:stoi、stringstream、scanf、to_string、sprintf
  6. 卷积神经网络(CNN)的细节问题(滤波器的大小选择)
  7. 集合类 collection接口 LinkedList
  8. Web前端--HTML+CSS+JS实现3D立体魔方小游戏
  9. newifimini出厂固件_新路由newifi固件
  10. dtu连接虚拟服务器,DTU连接HTTP网页
  11. 原理与结构解析——智能门锁方案
  12. 硅谷性能服务器介绍,美国RAKsmart服务器优势特点介绍
  13. 音频的相关基础知识,这里有
  14. pdps修改服务器,Tecnomatix PDPS二次开发功能介绍
  15. 【前端】Ajax-form表单与模板引擎
  16. 英超卡迪夫城新援飞机失联 搜救工作已经展开
  17. echarts柱状图数值差异过大和最小值无法选中的问题解决
  18. 流利说:通过数据分析评估获客效率
  19. 如何制作在线html游戏,如何做一个成功的网页游戏网站
  20. 手把手教你如何免费注册国际顶级域名

热门文章

  1. 北京理工大学计算机学院课程表,北京理工大学工业设计课程表.doc
  2. docker 进入mysql
  3. 绿色营销网站织梦模板源码
  4. QTabBar关闭按钮图标
  5. Kubernetes入门与进阶实战培训
  6. python简单单元测试示范卷,Python单元测试实例详解
  7. php利用socket_pair进程通信,Linux上实现双向进程间通信管道(socketpair)
  8. android中服务器返回0E-10是什么意思?
  9. matlab wsd,matlab-restplusgretna—MRI
  10. Java orm框架的优缺点_ORM框架简介及优缺点