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锁, ...
随机推荐
- javascript 小清新颜色翻页效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Study 7 —— CSS美化背景和边框
图片透明度属性:opacity 背景图片重复属性:background-repeat背景图片位置属性:background-position background-postion:横坐标 纵坐标; b ...
- ssm框架结构的搭建
ssm框架结构的搭建
- PageRank简单实现中的一个错误
在我的一篇博客PageRank中,在5.1 算法实现中简单实现部分原本是有一个错误的.这个错误也体现出我当时对PageRank算法有理解上的偏差. 这是个什么样的错误呢?是这样的: 简单实现中计算每个 ...
- string和list互转
import string str = 'abcde' list = list(str) OR list = str.split() list ['a', 'b', 'c', 'd', 'e'] st ...
- MyBatis参数传递
一.单个参数: public List<XXBean> getXXBeanList(String xxCode); <select id="getXXXBeanList&q ...
- 启动与关闭comcat服务器
1.找 comcat 安装目录 如 : E:\tomcat\apache-tomcat-7.0.64\bin 2.关闭comcat 服务 3.启动comcat服务
- luogu P1627 [CQOI2009]中位数
传送门 要求有多少个长度为奇数的区间满足某个数为区间中位数 这样的区间,大于中位数的数个数 等于 小于中位数的数个数 用类似于前缀和的方法,设\(X_i\)为\(i\)和数\(b\)形成的区间内,大于 ...
- python技巧 python2中的除法结果为0
在python2中执行除法操作如果结果小于1就会返回0 如下面的例子: >>>81/82 0 如果你需要返回"正确的结果 ",有两种方法: 在脚本中引入from ...
- C# List分页
假设你每页10条数据当前是第3页 跳到第4页则:List.Skip((4-1)*10).Take(10) 本文来自SunShine,转载请标明出处: http://do.jhost.cn/sunshi ...