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锁, ...
随机推荐
- Hive记录-impala常用命令
1.impala是什么 Impala是Cloudera公司主导开发的新型查询系统,它提供SQL语义,能查询存储在Hadoop的HDFS和HBase中的PB级大数据.已有的Hive系统虽然也提供了SQL ...
- POJ No.3255 Roadblocks 求次短路径
#define _CRT_SECURE_NO_WARNINGS /* 7 10 0 1 5 0 2 2 1 2 4 1 3 2 2 3 6 2 4 10 3 5 1 4 5 3 4 6 5 5 6 9 ...
- 04-接口隔离原则(ISP)
1. 背景 类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类B和类D来说不是最小接口,则类B和类D不得不去实现它们不需要的方法. 2. 定义 一个类对另一个类的依赖应该建立在最小的接口 ...
- VS2015 与 Git 的简单使用
前言 在白忙之中抽了点时间,记录了下 VS 与 Git 的简单使用. 在之前使用命令行的时候,提交或拉取代码时,总报错:(提取时遇到错误: Unsupported URL protocol),后来在网 ...
- 三、内存管理单元---MMU
3.1 MMU介绍 3.1.1 MMU 特性 内存管理单元(Memory Management Unit)简称MMU,它负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查.现在的多用户多进 ...
- drozer工具的安装与使用:之一安装篇
本教程针对于Windows平台下drozer的安装与使用 使用该工具需要JDK的支持,所以使用此工具之前请自行安装 JDK(如有问题的请自行百度其他教程,这里就不赘述了) 还需要安卓调试工具a ...
- JS禁止右键查看源码,禁止复制,复制内容到剪切板
有时候我们希望自己的网页源码不被查看,这时需要关掉鼠标的右击事件;有时候我们也希望禁止选择页面内容Ctrl+C复制. 1.禁止右键查看源码; <script> //设置右键事件 funct ...
- 用C++的 new 代替 C 的 malloc 进行内存分配
例子: (int*)malloc(100*sizeof(int)) 是先取得int类型的字节宽度,然后乘100计算后得到400,然后调用malloc,并将400传递给函数,分配400字节的内存空间,但 ...
- Linux 内核里的“智能指针”【转】
转自:http://blog.jobbole.com/88279/ 众所周知,C/C++语言本身并不支持垃圾回收机制,虽然语言本身具有极高的灵活性,但是当遇到大型的项目时,繁琐的内存管理往往让人痛苦异 ...
- css实现左(右)侧固定宽度,右(左)侧宽度自适应 ---清除浮动
老话长谈,css的不固定适应布局 不管是面试还是在平时的工作中,这样的布局形式一直都在用着,很常见,所以今天我就拿出来在唠叨一下, 既是给自己一个备忘存储,也是一个学习巩固的参考,知道大家都会,还 ...