本文介绍如何使用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防重复提交解决方案的更多相关文章

  1. spring MVC 后台token防重复提交解决方案

    看到公司有个部门提出了这个问题,补个粗略的解决方案... 1.编写拦截器 /** * Description: 防止重复提交 * * @Author liam * @Create Date: 2018 ...

  2. (亿级流量)分布式防重复提交token设计

    大型互联网项目中,很多流量都达到亿级.同一时间很多的人在使用,而每个用户提交表单的时候都可能会出现重复点击的情况,此时如果不做好控制,那么系统将会产生很多的数据重复的问题.怎样去设计一个高可用的防重复 ...

  3. 架构设计 | 接口幂等性原则,防重复提交Token管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.幂等性概念 1.幂等简介 编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.就是说,一次和多次请求某一个资源会产 ...

  4. (九)Struts2 防重复提交

    所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:重复提交示例演示 struts.xml <?xml version ...

  5. AJAX防重复提交的办法总结

    最近的维护公司的一个代理商平台的时候,客服人员一直反映说的统计信息的时候有重复数据,平台一直都很正常,这个功能是最近新进的一个实习生同事写的功能,然后就排查问题人所在,发现新的这个模块的AJAX提交数 ...

  6. struts2学习(15)struts2防重复提交

    一.重复提交的例子: 模拟一种情况,存在延时啊,系统比较繁忙啊啥的. 模拟延迟5s钟,用户点了一次提交,又点了一次提交,例子中模拟这种情况: 这样会造成重复提交:   com.cy.action.St ...

  7. 拦截器springmvc防止表单重复提交【1】

    [参考博客:http://www.cnblogs.com/hdwpdx/archive/2016/03/29/5333943.html] springmvc 用拦截器+token防止重复提交 首先,防 ...

  8. 使用aop注解实现表单防重复提交功能

    原文:https://www.cnblogs.com/manliu/articles/5983888.html 1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分 ...

  9. 浅谈C#在网络波动时防重复提交

    前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同).排查原因,发现是网络波动造成了重复提交. 由于网络波动而重复提交的例子也比较多: 网络上,防重复提交的方法也很多,使用redis锁, ...

随机推荐

  1. css before after基本用法【转】

    <HTML><HEAD> <meta http-equiv="content-Type"content="text/html;charset ...

  2. The connection to adb is down, and a severe error has occured(Android模拟器端口被占用)

    相信不少同学和我一样遇到这个问题,有时候搞的还要重启电脑,那究竟是什么原因导致的呢,很明显,你的端口被占用了,那下面给出终极解决方案 一.首先描述症状,如下图 二.出现问题了,首先确定你的sdk目录是 ...

  3. RunLoop 原理和核心机制

    搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研究了RunLoop的原理和特性. RunLoop的 ...

  4. Python提示AttributeError 或者DeprecationWarning: This module was deprecated解决方法

    Python提示AttributeError 或者DeprecationWarning: This module was deprecated解决方法 在使用Python的sklearn库时,发现sk ...

  5. MySQL内连接、外连接、交叉连接

    外连接: 左连接:left join 或 left outer join 以左边的表为基准,如果左表有数据,而右表没有数据,左表的数据正常显示,右表数据显示为空. 创建user表,用于记录用户 use ...

  6. 重新学习Servlet

    package javax.servlet; import java.io.IOException; public interface Servlet { public void init(Servl ...

  7. 【黑客免杀攻防】读书笔记2 - 免杀与特征码、其他免杀技术、PE进阶介绍

    第3章 免杀与特征码 这一章主要讲了一些操作过程.介绍了MyCCL脚本木马免杀的操作,对于定位特征码在FreeBuf也曾发表过类似工具. VirTest5.0特征码定位器 http://www.fre ...

  8. ll(ls -l) 列属性

    文件属性 文件数 拥有者 所属的group 文件大小 建档日期 文件名 drwx------ 2 Guest users 1024 Nov 21 21:05 Mail

  9. freeRTOS中文实用教程1--任务

    1.前言 FreeRTOS是小型多任务嵌入式操作系统,硬实时性.本章主要讲述任务相关特性及调度相关的知识. 2. 任务的总体特点 任务的状态 (1)任务有两个状态,运行态和非运行态 (2)任务由非运行 ...

  10. OLAP和OLTP的区别(基础知识) 【转】

    联机分析处理 (OLAP) 的概念最早是由关系数据库之父E.F.Codd于1993年提出的,他同时提出了关于OLAP的12条准则.OLAP的提出引起了很大的反响,OLAP作为一类产品同联机事务处理 ( ...