方案一:利用Session防止表单重复提交

具体的做法:
  1、获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌)。

2、将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。

3、服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。

看具体的范例:

1.创建FormServlet,用于生成Token(令牌)和跳转到form.jsp页面

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class FormServlet extends HttpServlet {private static final long serialVersionUID = -884689940866074733L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String token =  UUID.randomUUID().toString() ;//创建令牌System.out.println("在FormServlet中生成的token:"+token);request.getSession().setAttribute("token", token);  //在服务器使用session保存token(令牌)request.getRequestDispatcher("/form.jsp").forward(request, response);//跳转到form.jsp页面}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

2.在form.jsp中使用隐藏域来存储Token(令牌)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>form表单</title></head><body><form action="${pageContext.request.contextPath}/servlet/DoFormServlet" method="post"><%--使用隐藏域存储生成的token--%><%--<input type="hidden" name="token" value="<%=session.getAttribute("token") %>">--%><%--使用EL表达式取出存储在session中的token--%><input type="hidden" name="token" value="${token}"/> 用户名:<input type="text" name="username"> <input type="submit" value="提交"></form></body></html>3.DoFormServlet处理表单提交 import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class DoFormServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {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;}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

方案二:判断请求url和数据是否和上一次相同

推荐,非常简单,页面不需要任何传入,只需要在验证的controller方法上写上自定义注解即可

写好自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;  /** * 一个用户 相同url 同时提交 相同数据 验证 * @author Administrator * */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SameUrlData {  }

写好拦截器

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;  import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;  import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  import com.thinkgem.jeesite.common.mapper.JsonMapper;  /** * 一个用户 相同url 同时提交 相同数据 验证 * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单 * @author Administrator * */
public class SameUrlDataInterceptor  extends HandlerInterceptorAdapter{  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  if (handler instanceof HandlerMethod) {  HandlerMethod handlerMethod = (HandlerMethod) handler;  Method method = handlerMethod.getMethod();  SameUrlData annotation = method.getAnnotation(SameUrlData.class);  if (annotation != null) {  if(repeatDataValidator(request))//如果重复相同数据  return false;  else   return true;  }  return true;  } else {  return super.preHandle(request, response, handler);  }  }  /** * 验证同一个url数据是否相同提交  ,相同返回true * @param httpServletRequest * @return */  public boolean repeatDataValidator(HttpServletRequest httpServletRequest)  {  String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());  String url=httpServletRequest.getRequestURI();  Map<String,String> map=new HashMap<String,String>();  map.put(url, params);  String nowUrlParams=map.toString();//  Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");  if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面  {  httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);  return false;  }  else//否则,已经访问过页面  {  if(preUrlParams.toString().equals(nowUrlParams))//如果上次url+数据和本次url+数据相同,则表示城府添加数据  {  return true;  }  else//如果上次 url+数据 和本次url加数据不同,则不是重复提交  {  httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);  return false;  }  }  }  }
<mvc:interceptor>  <mvc:mapping path="/**"/>  <bean class="*.*.SameUrlDataInterceptor"/>
</mvc:interceptor>

方案三:利用Spring AOP和redis的锁来实现防止表单重复提交

主要是利用了redis的分布式锁机制

1、注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 防止重复提交注解
* @author zzp 2018.03.11
* @version 1.0
*/
@Retention(RetentionPolicy.RUNTIME) // 在运行时可以获取
@Target(value = {ElementType.METHOD, ElementType.TYPE})  // 作用到类,方法,接口上等
public @interface PreventRepetitionAnnotation {}

2、AOP代码

import java.lang.reflect.Method;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.com.rlid.utils.json.JsonBuilder;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import demo.zzp.app.aop.annotation.OperaterAnnotation;
import demo.zzp.app.redis.JedisUtils;
/**
* 防止重复提交操作AOP类
* @author zzp 2018.03.10
* @version 1.0
*/
@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class PreventRepetitionAspect {@Autowiredprivate JedisUtils jedisUtils;private static final String PARAM_TOKEN = "token";private static final String PARAM_TOKEN_FLAG =  "tokenFlag";/*** around* @throws Throwable*/@Around(value =  "@annotation(demo.zzp.app.aop.annotation.PreventRepetitionAnnotation)")public Object excute(ProceedingJoinPoint  joinPoint) throws Throwable{try {Object result = null;Object[] args = joinPoint.getArgs();for(int i = 0;i < args.length;i++){if(args[i] != null && args[i]  instanceof HttpServletRequest){HttpServletRequest request =  (HttpServletRequest) args[i];//被调用的方法需要加上HttpServletRequest request这个参数HttpSession session =  request.getSession();if(request.getMethod().equalsIgnoreCase("get")){//方法为getresult =  generate(joinPoint, request, session,  PARAM_TOKEN_FLAG);}else{//方法为postresult =  validation(joinPoint, request, session,  PARAM_TOKEN_FLAG);}}}return result;} catch (Exception e) {e.printStackTrace();return JsonBuilder.toJson(false, "操作失败!", "执行防止重复提交功能AOP失败,原因:" +  e.getMessage());}}public Object generate(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throws Throwable {String uuid = UUID.randomUUID().toString();request.setAttribute(PARAM_TOKEN, uuid);return joinPoint.proceed();}public Object validation(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throws Throwable {String requestFlag =  request.getParameter(PARAM_TOKEN);//redis加锁boolean lock =  jedisUtils.tryGetDistributedLock(tokenFlag +  requestFlag, requestFlag, 60000);if(lock){//加锁成功//执行方法Object funcResult = joinPoint.proceed();//方法执行完之后进行解锁jedisUtils.releaseDistributedLock(tokenFlag +  requestFlag, requestFlag);return funcResult;}else{//锁已存在return JsonBuilder.toJson(false, "不能重复提交!",  null);}}}

3、Controller代码

@RequestMapping(value = "/index",method =  RequestMethod.GET)
@PreventRepetitionAnnotationpublic String toIndex(HttpServletRequest  request,Map<String, Object> map){return "form";}@RequestMapping(value = "/add",method =  RequestMethod.POST)@ResponseBody@PreventRepetitionAnnotationpublic String add(HttpServletRequest request){try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return JsonBuilder.toJson(true, "保存成功!",null);}

第一次点击提交表单,判断到当前的token还没有上锁,即给该token上锁。如果连续点击提交,则提示不能重复提交,当上锁的那次操作执行完,redis释放了锁之后才能继续提交。

后台防止表单重复提交的三种方法相关推荐

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

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

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

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

  3. HTML表单重复按钮,防止表单重复提交的几种方法总结

    1.JavaScript防止表单重复提交(主要用于网络延迟情况下用户点击多次submit按钮导致表单重复提交) 在jsp页面中,添加JavaScript代码来防止表单的重复提交.主要是针对在网络延迟情 ...

  4. 防止form表单重复提交的几种方案

    阅读目录 前言 form重复提交场景 解决方案 一:前端利用JavaScript防止表单重复提交 二:利用Session防止表单重复提交 三:使用重定向也可以解决form表单重复提交问题 参考 前言 ...

  5. 后台防止表单重复提交

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

  6. java后端 防重复提交_后台防止表单重复提交

    具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送到客户端的Form表单中,在Form表单中使 ...

  7. python表单防重复提交_防止表单重复提交的几种策略

    表单重复提交是在多用户Web应用中最常见.带来很多麻烦的一个问题.有很多的应用场景都会遇到重复提交问题,比如: 点击提交按钮两次. 点击刷新按钮. 使用浏览器后退按钮重复之前的操作,导致重复提交表单. ...

  8. 防止表单重复提交的八种简单有效的策略

    表单重复提交是在多用户Web应用中最常见.带来很多麻烦的一个问题.有很多的应用场景都会遇到重复提交问题,比如: 点击提交按钮两次. 点击刷新按钮. 使用浏览器后退按钮重复之前的操作,导致重复提交表单. ...

  9. 【JavaWeb】jsp页面中表单重复提交的三种情况

    情况一 如通过regist.jsp页面提交用户名和密码申请注册,若注册成功,则将用户数据保存到数据库,并通过请求转发跳转到success.jsp页面. 此时在跳转后按F5刷新当前页面,则数据库会多次添 ...

最新文章

  1. Pandas 重复数据处理大全
  2. 113亿参数,中国最大 AI 模型!不仅能作诗,还能告诉你男朋友该不该分手!
  3. python 写cs程序_Python cs.cmdutils包_程序模块 - PyPI - Python中文网
  4. MySQL数据库自动添加时间戳
  5. 区块链是什么鬼,未来30万亿贷款市场或将激活?
  6. 字节3-1前端面试官自学Vue的正确姿势
  7. 利用python脚本程序监控文件被修改
  8. Python eval 与 exec 函数 - Python零基础入门教程
  9. 监督学习 | 线性回归 之多元线性回归原理及Sklearn实现
  10. 老师,你确定注释不会被执行吗?
  11. 静态RAM(1K X 4位)2114原理介绍(抄原理图)
  12. 小强的HTML5移动开发之路(14)——Video标签详解
  13. 雅虎网站页面性能优化的34条黄金守则
  14. 魅族mx4pro刷linux,魅族MX4 Pro刷recovery教程_魅族MX4 Pro第三方recovery下载
  15. STM32嵌入式基础开发07-使用PS2手柄遥控麦克纳姆轮小车(7_PS2_Veh)
  16. 最快倾斜摄影三维建模-台式、便携、多机集群配置推荐
  17. 重庆工程学院计算机设计大赛获奖名单,重大城科学子在2018年(第11届)中国大学生计算机设计大赛全国总决赛获一等奖...
  18. iBeacon工作原理
  19. OBS 基础 16 如何在CMake中添加新的lib库、头文件等
  20. 迪拜“烧掉800亿”造了座烂尾岛,奇葩建筑惊呆网友:有钱人的世界,我不懂!

热门文章

  1. 如何删除正在运行的dll文件
  2. python将图片转换成动漫_python实现图片转换成素描和漫画格式
  3. 小谈向量内积与函数内积
  4. 关于safari浏览器 New Date() 为NaN 的兼容
  5. Macbook搭建vue开发环境
  6. Spyder IDE 安装
  7. 获取滚动条宽度(Element-UI之三)
  8. Oracle默认端口清单
  9. 如何获取物体立体信息通过一个相机
  10. Oracle pivot函数解析与使用