当前位置:   article > 正文

防止form表单提交的几种方式_阻止form表单提交

阻止form表单提交

1. 背景介绍

在开发项目中肯可能会出现如下情况:

     1. 用户的失误操作,多次点击表单提交按钮

     2. 由于网速等原因造成页面卡顿,用户重复刷新提交页面

     3. 黑客或恶意用户使用postman等工具重复恶意提交表单

....

这些情况都会导致表单的重复提交,导致数据重复,增加服务器的压力,甚至会造成服务器宕机,因此要有效防止表单重复提交非常必要。

2. 解决方案

2.1 点击一次之后,按钮失效(不推荐,用户刷新页面仍能重复提交)

      通过js代码,当用户点击提交按钮后,屏蔽提交按钮(使按钮无发点击提交或点击无效disabled),从而实现防止表单重复提交。

2.2 用redirect来解决重复提交问题

   简而言之,表单提交后重定向到提交成功的一个页面。

2.3在数据库里添加约束

    在数据库里添加唯一约束或创建唯一索引,防止出现重复数据。简单粗暴的方法。

2.4 在session中存放一个特殊标志(推荐)

     类似于“令牌”机制。当表单页面第一次被请求时,生成一个特殊的字符标志串,存在session中,同时放在表单的隐藏域里。接受处理表单数据时,检查标识字串是否存在,若标志串相同则处理表单提交并立即从session中删除它。若不一致就是重复提交了则忽略这次提交。如果发现表单提交里没有有效的标志串,这说明表单已经被提交过了,忽略这次提交。

(解决struts2重复提交,可以结合s:token标签解决重复提交问题)

2.5 使用AOP自定义切入实现

实现原理:

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

自定义标签

  1. import java.lang.annotation.*;
  2. /**
  3. * 避免重复提交
  4. * @author dsx
  5. * @version
  6. * @since
  7. */
  8. @Target(ElementType.METHOD)
  9. @Retention(RetentionPolicy.RUNTIME)
  10. public @interface AvoidRepeatableCommit {
  11. /**
  12. * 指定时间内不可重复提交,单位毫秒
  13. * @return
  14. */
  15. long timeout() default 30000 ;
  16. }

自定义切面Aspect

  1. /**
  2. * 解决重复提交aop
  3. * @author dsx
  4. * @version
  5. * @since
  6. */
  7. @Aspect
  8. @Component
  9. public class AvoidRepeatableCommitAspect {
  10. @Autowired
  11. private RedisTemplate redisTemplate;
  12. /**
  13. * @param point
  14. */
  15. @Around("@annotation(com.xwolf.boot.annotation.AvoidRepeatableCommit)")
  16. public Object around(ProceedingJoinPoint point) throws Throwable {
  17. HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
  18. String ip = IPUtil.getIP(request);
  19. //获取注解
  20. MethodSignature signature = (MethodSignature) point.getSignature();
  21. Method method = signature.getMethod();
  22. //目标类、方法
  23. String className = method.getDeclaringClass().getName();
  24. String name = method.getName();
  25. String ipKey = String.format("%s#%s",className,name);
  26. int hashCode = Math.abs(ipKey.hashCode());
  27. String key = String.format("%s_%d",ip,hashCode);
  28. log.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);
  29. AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
  30. long timeout = avoidRepeatableCommit.timeout();
  31. if (timeout < 0){
  32. //过期时间5分钟
  33. timeout = 60*5;
  34. }
  35. String value = (String) redisTemplate.opsForValue().get(key);
  36. if (StringUtils.isNotBlank(value)){
  37. return "请勿重复提交";
  38. }
  39. redisTemplate.opsForValue().set(key, UUIDUtil.uuid(),timeout,TimeUnit.MILLISECONDS);
  40. //执行方法
  41. Object object = point.proceed();
  42. return object;
  43. }
  44. }

如有不足,望不吝赐教!!!

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号