具体的做法:

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

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

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

看具体的范例:

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

importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class FormServlet extendsHttpServlet {private static final long serialVersionUID = -884689940866074733L;public voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, 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 voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

doGet(request, response);

}

}

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

form表单

">

--%>

用户名:

3.DoFormServlet处理表单提交

importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class DoFormServlet extendsHttpServlet {public voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {boolean b = isRepeatSubmit(request);//判断用户是否是重复提交

if(b==true){

System.out.println("请不要重复提交");return;

}

request.getSession().removeAttribute("token");//移除session中的token

System.out.println("处理用户提交请求!!");

}/*** 判断客户端提交上来的令牌和服务器端生成的令牌是否一致

*@paramrequest

*@return* true 用户重复提交了表单

* false 用户没有重复提交表单*/

private booleanisRepeatSubmit(HttpServletRequest request) {

String client_token= request.getParameter("token");//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单

if(client_token==null){return true;

}//取出存储在Session中的token

String 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 voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

doGet(request, response);

}

}

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

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

写好自定义注解

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** 一个用户 相同url 同时提交 相同数据 验证

*@authorAdministrator

**/@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)public @interfaceSameUrlData {

}

写好拦截器

importjava.lang.reflect.Method;importjava.util.HashMap;importjava.util.Map;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importcom.thinkgem.jeesite.common.mapper.JsonMapper;/*** 一个用户 相同url 同时提交 相同数据 验证

* 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单

*@authorAdministrator

**/

public class SameUrlDataInterceptor extendsHandlerInterceptorAdapter{

@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {if (handler instanceofHandlerMethod) {

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

*@paramhttpServletRequest

*@return

*/

public booleanrepeatDataValidator(HttpServletRequest httpServletRequest)

{

String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());

String url=httpServletRequest.getRequestURI();

Map map=new HashMap();

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;

}

}

}

}

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

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

1、注解:

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** 防止重复提交注解

*@authorzzp 2018.03.11

*@version1.0*/@Retention(RetentionPolicy.RUNTIME)//在运行时可以获取

@Target(value = {ElementType.METHOD, ElementType.TYPE})  //作用到类,方法,接口上等

public @interfacePreventRepetitionAnnotation {

}

2、AOP代码

importjava.lang.reflect.Method;importjava.util.UUID;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpSession;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.reflect.MethodSignature;importorg.com.rlid.utils.json.JsonBuilder;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.EnableAspectJAutoProxy;importorg.springframework.stereotype.Component;importdemo.zzp.app.aop.annotation.OperaterAnnotation;importdemo.zzp.app.redis.JedisUtils;/*** 防止重复提交操作AOP类

*@authorzzp 2018.03.10

*@version1.0*/@Aspect

@Component

@EnableAspectJAutoProxy(proxyTargetClass=true)public classPreventRepetitionAspect {

@AutowiredprivateJedisUtils jedisUtils;private static final String PARAM_TOKEN = "token";private static final String PARAM_TOKEN_FLAG =  "tokenFlag";/*** around

*@throwsThrowable*/@Around(value=  "@annotation(demo.zzp.app.aop.annotation.PreventRepetitionAnnotation)")public Object excute(ProceedingJoinPoint  joinPoint) throwsThrowable{try{

Object result= null;

Object[] args=joinPoint.getArgs();for(int i = 0;i < args.length;i++){if(args[i] != null && args[i]  instanceofHttpServletRequest){

HttpServletRequest request=  (HttpServletRequest) args[i];//被调用的方法需要加上HttpServletRequest request这个参数

HttpSession session =request.getSession();if(request.getMethod().equalsIgnoreCase("get")){//方法为get

result =generate(joinPoint, request, session,  PARAM_TOKEN_FLAG);

}else{//方法为post

result =validation(joinPoint, request, session,  PARAM_TOKEN_FLAG);

}

}

}returnresult;

}catch(Exception e) {

e.printStackTrace();return JsonBuilder.toJson(false, "操作失败!", "执行防止重复提交功能AOP失败,原因:" +e.getMessage());

}

}public Object generate(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throwsThrowable {

String uuid=UUID.randomUUID().toString();

request.setAttribute(PARAM_TOKEN, uuid);returnjoinPoint.proceed();

}public Object validation(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throwsThrowable {

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);returnfuncResult;

}else{//锁已存在

return JsonBuilder.toJson(false, "不能重复提交!",  null);

}

}

}

3、Controller代码

@RequestMapping(value = "/index",method =RequestMethod.GET)

@PreventRepetitionAnnotationpublic String toIndex(HttpServletRequest  request,Mapmap){return "form";

}

@RequestMapping(value= "/add",method =RequestMethod.POST)

@ResponseBody

@PreventRepetitionAnnotationpublicString add(HttpServletRequest request){try{

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}return JsonBuilder.toJson(true, "保存成功!",null);

}

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

java后端 防重复提交_后台防止表单重复提交相关推荐

  1. java怎么防止表单重复提交_如何防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

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

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

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

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

  4. 大聪明教你学Java | Spring Boot 使用自定义注解实现防止表单重复提交

    前言 表单重复提交是在多用户的 Web 应用中最常见且带来麻烦最多的一个问题.有很多的应用场景都会遇到表单重复提交问题,比如由于用户误操作,多次点击表单提交按钮:由于网速等原因造成页面卡顿,用户重复刷 ...

  5. 表单防止多次提交php,php防止表单重复提交

    后端防止重复提交的基本原理: 服务器返回表单页面时,会先生成一个subToken保存于session,并把该subToen传给表单页面.当表单提交时会带上subToken,服务器获取表单信息判断ses ...

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

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

  7. php 判断提交表单提交,php判断form表单是否提交详解

    php判断表单是否提交 我们一般通过 submit 提交表单时,会在乎在表单中填写的一大堆数据是否提交到后台.这里就需要做个判断,使用php代码来判断表单数据是否被提交一般采用如下的形式:<?p ...

  8. Java后端接收前端post方式传来的表单数据

    可以通过HttpServletRequest和@RequestParam注解来获取post提交的表单数据 1.使用HttpServletRequest来获取 @PostMapping(value = ...

  9. java表单重复提交_JavaWeb防止表单重复提交(转载)

    转载自:http://blog.csdn.net/ye1992/article/details/42873219 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用 ...

最新文章

  1. windows10中git 远程仓库使用
  2. NYOJ 595 乱七八糟
  3. hdu4091(暴力)
  4. 使用SharedPreferences存储和读取数据
  5. python抽奖滚动界面_Python使用Tkinter实现转盘抽奖器的步骤详解
  6. 海思3519A配置NFS文件系统(永久)
  7. 人工智能知识体系的学习路线(南京大学人工智能学院本科生培养体系)
  8. 解决Sublime Text 2中文显示乱码问题
  9. 贪吃蛇c语言代贴吧,【图片】C语言小游戏~贪吃蛇【c语言吧】_百度贴吧
  10. 淦!看了 B 站上的这些 Python 视频,我站起来了!
  11. c51单片机跑马灯汇编语言,单片机的跑马灯简单汇编程序
  12. MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了
  13. HDOJ 5620-KK's Steel【斐波那契数列】
  14. 解决Apache提示“You don‘t have permission to access...“错误
  15. PhotoShop PS液化抖动 使用液化时,鼠标、数位板光标抖动
  16. 考试酷c语言程序设计的答案大全,FX-TRN-BEG-C 考试酷 V-MECA组合在PLC项目教学中的运用...
  17. 如春日细雨般的缠绵,浸润心扉
  18. Matlab使用入门及应用
  19. Oracle数据库的可视化界面
  20. 【实战】文本驱动的StyleGAN2图像处理(二):潜码映射器(Latent Mapper)

热门文章

  1. c语言 case break,C语言中switch...case语句中break的重要性
  2. MATLAB GUI 界面编程——常见问题和解决方法
  3. Spring的IOC(控制反转)与DI(依赖注入)
  4. MySQL事务隔离级别以及实现原理
  5. 茄子python_python笔记一
  6. 【上新】神秘的 Gotchiverse 艺术版本来袭,将带来三个惊喜新功能!
  7. mysql导入数据库_mysql 导入数据库 命令操作
  8. 微信“拍一拍”功能只为好玩?我却看到微信如芒在背,害怕什么?
  9. 整理查找的鼠标悬浮移入移出事件
  10. 关于油猴被浏览器禁止访问的解决办法