java后端 防重复提交_后台防止表单重复提交
具体的做法:
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后端 防重复提交_后台防止表单重复提交相关推荐
- java怎么防止表单重复提交_如何防止表单重复提交
在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...
- 后台防止表单重复提交
方案一:利用Session防止表单重复提交 具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送 ...
- 后台防止表单重复提交的三种方法
方案一:利用Session防止表单重复提交 具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送 ...
- 大聪明教你学Java | Spring Boot 使用自定义注解实现防止表单重复提交
前言 表单重复提交是在多用户的 Web 应用中最常见且带来麻烦最多的一个问题.有很多的应用场景都会遇到表单重复提交问题,比如由于用户误操作,多次点击表单提交按钮:由于网速等原因造成页面卡顿,用户重复刷 ...
- 表单防止多次提交php,php防止表单重复提交
后端防止重复提交的基本原理: 服务器返回表单页面时,会先生成一个subToken保存于session,并把该subToen传给表单页面.当表单提交时会带上subToken,服务器获取表单信息判断ses ...
- 5位随机数重复的概率 php_php防止表单重复提交的方法
Token,就是令牌,最大的特点就是随机性,不可预测. Token一般用在两个地方--防止表单重复提交.anti csrf攻击(跨站点请求伪造). 两者在原理上都是通过session token来实现 ...
- php 判断提交表单提交,php判断form表单是否提交详解
php判断表单是否提交 我们一般通过 submit 提交表单时,会在乎在表单中填写的一大堆数据是否提交到后台.这里就需要做个判断,使用php代码来判断表单数据是否被提交一般采用如下的形式:<?p ...
- Java后端接收前端post方式传来的表单数据
可以通过HttpServletRequest和@RequestParam注解来获取post提交的表单数据 1.使用HttpServletRequest来获取 @PostMapping(value = ...
- java表单重复提交_JavaWeb防止表单重复提交(转载)
转载自:http://blog.csdn.net/ye1992/article/details/42873219 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用 ...
最新文章
- windows10中git 远程仓库使用
- NYOJ 595 乱七八糟
- hdu4091(暴力)
- 使用SharedPreferences存储和读取数据
- python抽奖滚动界面_Python使用Tkinter实现转盘抽奖器的步骤详解
- 海思3519A配置NFS文件系统(永久)
- 人工智能知识体系的学习路线(南京大学人工智能学院本科生培养体系)
- 解决Sublime Text 2中文显示乱码问题
- 贪吃蛇c语言代贴吧,【图片】C语言小游戏~贪吃蛇【c语言吧】_百度贴吧
- 淦!看了 B 站上的这些 Python 视频,我站起来了!
- c51单片机跑马灯汇编语言,单片机的跑马灯简单汇编程序
- MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了
- HDOJ 5620-KK's Steel【斐波那契数列】
- 解决Apache提示“You don‘t have permission to access...“错误
- PhotoShop PS液化抖动 使用液化时,鼠标、数位板光标抖动
- 考试酷c语言程序设计的答案大全,FX-TRN-BEG-C 考试酷 V-MECA组合在PLC项目教学中的运用...
- 如春日细雨般的缠绵,浸润心扉
- Matlab使用入门及应用
- Oracle数据库的可视化界面
- 【实战】文本驱动的StyleGAN2图像处理(二):潜码映射器(Latent Mapper)
热门文章
- c语言 case break,C语言中switch...case语句中break的重要性
- MATLAB GUI 界面编程——常见问题和解决方法
- Spring的IOC(控制反转)与DI(依赖注入)
- MySQL事务隔离级别以及实现原理
- 茄子python_python笔记一
- 【上新】神秘的 Gotchiverse 艺术版本来袭,将带来三个惊喜新功能!
- mysql导入数据库_mysql 导入数据库 命令操作
- 微信“拍一拍”功能只为好玩?我却看到微信如芒在背,害怕什么?
- 整理查找的鼠标悬浮移入移出事件
- 关于油猴被浏览器禁止访问的解决办法