【Java必备技能二】防止表单重复提交方法

一、简介

最近在项目中,有一个用户移动端打卡上班的功能,如果短时间内快速双击几次打卡按钮的话,数据库会生成几条一模一样的打卡记录,很明显这就是重复提交数据了。

表单重复提交的几种情况:

  1. 由于用户误操作,多次点击表单提交按钮;
  2. 由于网速等原因造成页面卡顿,用户重复刷新提交页面;
  3. 黑客或恶意用户使用postman等工具重复恶意提交表单(攻击网站);

以上这些情况都会导致表单重复提交,造成数据重复,增加服务器负载,严重甚至会造成服务器宕机。因此有效防止表单重复提交有一定的必要性。

二、解决方案

一般需要防止表单重复提交的话,可以从前端表单按钮提交事件、限制后端接口调用、数据库唯一约束三个方面同时进行,多维度结合可以有效防止产生重复的垃圾数据。

【a】前端表单按钮提交事件

这种方式是修改前端表单提交按钮事件,可以在点击打卡的时候给一个“loading”加载中的状态或者禁用掉提交按钮,防止用户重复点击按钮导致重复发几次一样的请求。

【b】数据库唯一约束

这种我感觉是最简单粗暴的方式,直接在数据库加一个唯一约束,这样就不可能存在多条一模一样的数据,例如打卡时间精确到"10:30"分,那么我们可以通过建立【打卡类型(上班、下班)、打卡人、打卡分钟数】这三个字段的组合唯一约束,有效防止重复数据产生。

【c】限制后端接口调用

通过后端方式防止表单重复提交,实际上就是防止一个接口短时间不能被同一个客户端重复调用多次,所以这里需要使用【调用的目标方法的全限定名 + 客户端IP作为重复调用的判断标志】。这里我采用了Spring AOP切面来实现࿰

已标记关键词 清除标记
看了一下网上的案例,大部分都是自定义注解加拦截器实现防止表单重复提交 自定义注解: ``` @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FormToken { boolean save() default false; boolean remove() default false; } ``` 拦截器: ``` public class TokenInterceptor extends HandlerInterceptorAdapter { 14 private static final Logger LOG = Logger.getLogger(Token.class); 15 @Override 16 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 17 if (handler instanceof HandlerMethod) { 18 HandlerMethod handlerMethod = (HandlerMethod) handler; 19 Method method = handlerMethod.getMethod(); 20 Token annotation = method.getAnnotation(Token.class); 21 if (annotation != null) { 22 boolean needSaveSession = annotation.save(); 23 if (needSaveSession) { 24 request.getSession(true).setAttribute("token", UUID.randomUUID().toString()); 25 } 26 boolean needRemoveSession = annotation.remove(); 27 if (needRemoveSession) { 28 if (isRepeatSubmit(request)) { 29 LOG.warn("please don't repeat submit,url:"+ request.getServletPath()); 30 return false; 31 } 32 request.getSession(true).removeAttribute("token"); 33 } 34 } 35 return true; 36 } else { 37 return super.preHandle(request, response, handler); 38 } 39 } 40 41 private boolean isRepeatSubmit(HttpServletRequest request) { 42 String serverToken = (String) request.getSession(true).getAttribute("token"); 43 if (serverToken == null) { 44 return true; 45 } 46 String clinetToken = request.getParameter("token"); 47 if (clinetToken == null) { 48 return true; 49 } 50 if (!serverToken.equals(clinetToken)) { 51 return true; 52 } 53 return false; 54 } 55 } ``` 24行 request.getSession(true).setAttribute("token", UUID.randomUUID().toString()); 将token保存到session这里不是很理解,这里session的key已经写死了,如果多个人同时进行表单提交,那么session会不会被覆盖(因为key是一样的,后面新的session会覆盖前面的session)?
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值