SpringMVC后台token防重复提交解决方案
本文介绍如何使用token来防止前端重复提交的问题。
目录
- 1.思路
- 2.拦截器源码实现
- 3.注解源码
- 4.拦截器的配置
- 5.使用指南
- 6.结语
思路
1.添加拦截器,拦截需要防重复提交的请求
2.通过注解@Token来添加token/移除token
3.前端页面表单添加(如果是Ajax请求则需要在请求的json数据中添加token值)
核心源码
拦截器源码实现
/**
* com.xxx.interceptor.TokenInterceptor.java
* Copyright 2018 Lifangyu, Inc. All rights reserved.
*/
package com.xxx.common.interceptor;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Random;
import java.util.UUID;
/**
* Desc:防重复提交的拦截器
* <p>
* Created by lifangyu on 2018/02/27.
*/
public class TokenInterceptor extends HandlerInterceptorAdapter {
Logger logger = Logger.getLogger(TokenInterceptor.class);
static String splitFlag = "_";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Token annotation = method.getAnnotation(Token.class);
if (annotation == null) {
return true;
}
boolean needSaveSession = annotation.add();
if (needSaveSession) {
Random random = new Random();
String uuid = UUID.randomUUID().toString().replace(splitFlag, String.valueOf(random.nextInt(100000)));
String tokenValue = String.valueOf(System.currentTimeMillis());
request.setAttribute("token", uuid + splitFlag + tokenValue);
// session 中 token 的key 每次都是变化的[适应浏览器 打开多个带有token的页面不会有覆盖session的key]
request.getSession(true).setAttribute(uuid, tokenValue);
}
boolean needRemoveSession = annotation.remove();
if (needRemoveSession) {
if (isRepeatSubmit(request)) {
logger.warn("please don't repeat submit,url:" + request.getServletPath());
return false;
}
String clinetToken = request.getParameter("token");
if (clinetToken != null && clinetToken.indexOf(splitFlag) > -1) {
request.getSession(true).removeAttribute(clinetToken.split("_")[0]);
}
}
return true;
} else {
return super.preHandle(request, response, handler);
}
}
/**
* 判断是否是重复提交
*
* @param request
* @return
*/
private boolean isRepeatSubmit(HttpServletRequest request) {
String clinetToken = request.getParameter("token");
if (clinetToken == null) {
return true;
}
String uuid = clinetToken.split("_")[0];
String token = clinetToken.split("_")[1];
String serverToken = (String) request.getSession(true).getAttribute(uuid);
if (serverToken == null) {
return true;
}
if (!serverToken.equals(token)) {
return true;
}
return false;
}
}
注解源码
/**
* com.xxx.interceptor.Token.java
* Copyright 2018 Lifangyu, Inc. All rights reserved.
*/
package com.xxx.common.interceptor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Desc:Token 注解
* <p>
* Created by lifangyu on 2018/02/27.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
/**
* 添加token的开关[true:添加;false:不添加,default:false]
*
* @return
*/
boolean add() default false;
/**
* 移除token的开关[true:删除;false:不删除,default:false]
*
* @return
*/
boolean remove() default false;
}
拦截器的配置
在springMVC的servlet配置文件中配置拦截器
<!-- 拦截器配置 -->
<mvc:interceptors>
<!-- 配置Token拦截器,防止用户重复提交数据 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xxx.interceptor.TokenInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
使用指南
1.在进入页面的controller方法上添加注解@Token(add=true)
@Token(add = true)
@RequestMapping("toXxxHtml")
public String toXxxHtml(Model mv) {
......
return "xxx/xxxHtml";
}
2.在页面toXxxHtml.html添加
<form id="xxx_submit_form" class="form-horizontal" action="${ctx}/xxx/addXxx.do" method="post">
......
<!-- 注:name必须是token -->
<input type="hidden" name="token" value="${token!''}"/>
......
</form>
3.在防止重复提交的controller方法上添加@Token(remove = true)
@Token(remove = true)
@RequestMapping("addXxx")
public String addXxx() throws Exception {
......
return "redirect:toXxxHtml.do";
}
结语
到此本文就结束了,欢迎大家继续关注更多Spring案例。
扫描下面二维码,关注我的公众号哦!!!
SpringMVC后台token防重复提交解决方案的更多相关文章
- spring MVC 后台token防重复提交解决方案
看到公司有个部门提出了这个问题,补个粗略的解决方案... 1.编写拦截器 /** * Description: 防止重复提交 * * @Author liam * @Create Date: 2018 ...
- (亿级流量)分布式防重复提交token设计
大型互联网项目中,很多流量都达到亿级.同一时间很多的人在使用,而每个用户提交表单的时候都可能会出现重复点击的情况,此时如果不做好控制,那么系统将会产生很多的数据重复的问题.怎样去设计一个高可用的防重复 ...
- 架构设计 | 接口幂等性原则,防重复提交Token管理
本文源码:GitHub·点这里 || GitEE·点这里 一.幂等性概念 1.幂等简介 编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.就是说,一次和多次请求某一个资源会产 ...
- (九)Struts2 防重复提交
所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:重复提交示例演示 struts.xml <?xml version ...
- AJAX防重复提交的办法总结
最近的维护公司的一个代理商平台的时候,客服人员一直反映说的统计信息的时候有重复数据,平台一直都很正常,这个功能是最近新进的一个实习生同事写的功能,然后就排查问题人所在,发现新的这个模块的AJAX提交数 ...
- struts2学习(15)struts2防重复提交
一.重复提交的例子: 模拟一种情况,存在延时啊,系统比较繁忙啊啥的. 模拟延迟5s钟,用户点了一次提交,又点了一次提交,例子中模拟这种情况: 这样会造成重复提交: com.cy.action.St ...
- 拦截器springmvc防止表单重复提交【1】
[参考博客:http://www.cnblogs.com/hdwpdx/archive/2016/03/29/5333943.html] springmvc 用拦截器+token防止重复提交 首先,防 ...
- 使用aop注解实现表单防重复提交功能
原文:https://www.cnblogs.com/manliu/articles/5983888.html 1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分 ...
- 浅谈C#在网络波动时防重复提交
前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同).排查原因,发现是网络波动造成了重复提交. 由于网络波动而重复提交的例子也比较多: 网络上,防重复提交的方法也很多,使用redis锁, ...
随机推荐
- PHP7 学习笔记(七)如何使用zephir编译一个扩展记录
一.zephir 编译遇到的错误 安装 git clone https://github.com/phalcon/zephir $ cd zephir $ ./install-json $ ./ins ...
- java中常用的包及作用
1. java.awt:提供了绘图和图像类,主要用于编写GUI程序,包括按钮.标签等常用组件以及相应的事件类. 2. java.lang:java的语言包,是核心包,默认导入到用户程序,包中有obje ...
- 转--python -- 收发邮件
官方 import smtplib from email.mime.text import MIMEText from email.header import Header # 发送邮箱服务器 smt ...
- 关于Meta标签的一些知识
1.定义文档的编码格式(H5的标准写法) <meta charset="UTF-8"> 2.声明指定的浏览器以及版本 <meta http-equiv=" ...
- HTML中 等6种空白空格的区别
HTML提供了5种空格实体(space entity),它们拥有不同的宽度,非断行空格( )是常规空格的宽度,可运行于所有主流浏览器.其他几种空格( )在不同浏览器中宽度各异. 它 ...
- Linux 4.10.8 根文件系统制作(三)---制作yaffs文件系统
这里直接用的是韦东山提供的工具. yaffs文件系统是专门用于nandflash的文件系统 我们前面已经下载了yaffs 的源码,也做了文件系统目录的构建. 在yaffs2的源码目录中有一个utils ...
- 20155332 2016-2017-2 《Java程序设计》第6周学习总结
20155332 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 1.文件的读写 2.网络上传数据的基础 3.认识INputStream.OutputStre ...
- Linux - 账户切换授权
sudo 切换账户 echo myPassword | sudo -S ls /tmp # 直接输入sudo的密码非交互,从标准输入读取密码而不是终端设备 visudo # sudo命令权限添加 /e ...
- IO流总结笔记三
字节流: 抽象基类:InputStream, OutputStream. 字节流可以操作任何数据.注意:字符流使用的数组是字符数组.Char [] chs 字节流使用的数组是字节数组.Byte [ ...
- drozer工具的安装与使用:之二使用篇
如果英文好的同学可以直接查看官方文档 官方文档连接:https://labs.mwrinfosecurity.com/assets/BlogFiles/mwri-drozer-user-guide ...