原文:https://www.cnblogs.com/manliu/articles/5983888.html

1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分别放到session和request中,表单页面用一个隐藏域储存该token_flag,在提交表单时,将该token_flag一并提交到后台,后台将该token_flag和session中对比,只要比对通过就立即删除session中的token_flag,这样就能保证表单最多只有一次成功提交的机会。

2.表单防重复提交一般前后端都会做,前端比较简单,点击过一次就将提交按钮置灰或disabled。

3.因为生成和验证token_flag具有通用性,一般不建议嵌入到具体方法中,最好的方法就是使用aop+注解的方式

4.注解

/**
* 表单注解,放在需要验证表单的方法上,一般是controller上
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface FormToken { }

5.AOP

@Aspect
@Component
public class ResubmitAspect {
private static final String PARAM_TOKEN = "token";
private static final String PARAM_TOKEN_FLAG = "TokenFlag_"; /**
* 执行切面拦截逻辑
*/
@Around("@annotation(formToken)")
public void execute(ProceedingJoinPoint joinPoint, FormToken formToken) throws Throwable {
if (formToken != null) {
//方法入参列表
Object[] args = joinPoint.getArgs();
//类名
String className = joinPoint.getTarget().getClass().getName();
for (Object arg : args) {
//方法入参是否包含request
if (arg != null && arg instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) arg;
HttpSession session = request.getSession(true);
if ("GET".equalsIgnoreCase(request.getMethod())) {
/* GET 生成 token */
this.generate(joinPoint, request, session, PARAM_TOKEN_FLAG + className);
} else {
/* POST 验证 token */
this.validation(joinPoint, request, session, PARAM_TOKEN_FLAG + className);
}
}
}
}
}
/**
* <p>
* 生成表单 token
* </p>
*/
public void generate(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpSession session,
String tokenFlag) throws Throwable {
String uuid = UUID.randomUUID().toString();
session.setAttribute(tokenFlag, uuid);
request.setAttribute(PARAM_TOKEN, uuid);
joinPoint.proceed();
}
/**
* <p>
* 验证表单 token
* </p>
* <p>
* 验证结果一致,既为第一次提交,删除会话中存储的token,并继续执行方法。<br>
* 否则不做任何处理。
* </p>
*/
public void validation(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpSession session,
String tokenFlag) throws Throwable {
Object sessionFlag = session.getAttribute(tokenFlag);
Object requestFlag = request.getParameter(PARAM_TOKEN);
if (sessionFlag != null && sessionFlag.equals(requestFlag)) {
//删除已验证的token
session.removeAttribute(tokenFlag);
joinPoint.proceed();
}
}
}

6.配置

在spring配置文件中

<aop:aspectj-autoproxy />
<context:component-scan base-package="com.baomidou.framework.aop">
</context:component-scan>

7.html中使用

<input type="hidden" name="token" value="${token}" />

使用aop注解实现表单防重复提交功能的更多相关文章

  1. Spring MVC表单防重复提交

    利用Spring MVC的过滤器及token传递验证来实现表单防重复提交. 创建注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RU ...

  2. Token注解防止表单的重复提交

    注解的一些基础: 参见http://blog.csdn.net/duo2005duo/article/details/50505884和 http://blog.csdn.net/duo2005duo ...

  3. struts2 文件的上传下载 表单的重复提交 自定义拦截器

    文件上传中表单的准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设 ...

  4. php中如何防止表单的重复提交

    在php中如何防止表单的重复提交?其实也有几种解决方法. 下面小编就为大家介绍一下吧.需要的朋友可以过来参考下 代码: <?php /* * php中如何防止表单的重复提交 * by www.j ...

  5. php-- 避免表单的重复提交

    用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题.我们可以从客户端和服务器端一起着手,设法避免同一表单的重复提交. 1.使用客户端脚本 提 ...

  6. Session机制三(表单的重复提交)

    1.表单的重复提交的情况 在表单提交到一个servlet,而servlet又通过请求转发的方式响应了一个JSP页面,这个时候地址栏还保留这servlet的那个路径,在响应页面点击刷新. 在响应页面没有 ...

  7. HttpSession解决表单的重复提交

    1). 重复提交的情况: ①. 在表单提交到一个 Servlet, 而 Servlet 又通过请求转发的方式响应一个 JSP(HTML) 页面, 此时地址栏还保留着 Serlvet 的那个路径, 在响 ...

  8. Struts2 - 表单的重复提交问题

    用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此,重复提 ...

  9. HttpSession之表单的重复提交 & 验证码

    如果采用 HttpServletResponse.sendRedirct() 方法将客户端重定向到成功页面,将不会出现重复提交问题 1.表单的重复提交 1). 重复提交的情况: ①. 在表单提交到一个 ...

随机推荐

  1. ubuntu18.04连接pptpd服务器(未成功)

    sudo apt-get install pptp-linux sudo pptpsetup --create testvpn --server 127.0.0.1 --username your_u ...

  2. LODOP设置打印份数及是否逐份输出

    LODOP中通过SET_PRINT_COPIES可以设置打印份数,例如:LODOP.SET_PRINT_COPIES(2);//指定份数为2份 如果一个任务里有多页,打印份数的时候,有两种输出方式,一 ...

  3. bootstrap模态框怎么传递参数

    bootstrap参数传递可以用 data-参数名 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml&qu ...

  4. 【Leetcode_easy】844. Backspace String Compare

    problem 844. Backspace String Compare solution1: class Solution { public: bool backspaceCompare(stri ...

  5. 原生JavaScript判断浏览器对CSS属性是否支持

    /*判断浏览器是否支持某个css属性*/ function SupportCss(attrName){ var i=0, arr = SupportCss.opt.aBrowser, eleStyle ...

  6. orleans 的一种模式

    为了避免过热的grain,按时间%cpu数,分派任务到grain中,然后有限制的去访问原来过热的grain.eg:tokengrain,1个半小时后,更新所有的grain.

  7. 开启Hadoop和Spark的学习之路

    Hadoop Hadoop是一个由Apache基金会所开发的分布式系统基础架构. 用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储. Hadoop实现了一个 ...

  8. qt qml 类型之Keys

    Keys 类是 Qt Quick 提供的,专门供 Item 处理按键事件的类.它定义了很多针对特定按键的信号,比如 onReturnPressed / onEscapePressed / onDown ...

  9. 字符串char vchar性能对比补充

    Value CHAR(4) Storage Required VARCHAR(4) Storage Required '' '    ' 4 bytes '' 1 byte 'ab' 'ab  ' 4 ...

  10. Python进阶:metaclass谈

    metaclass 的超越变形特性有什么用? 来看yaml的实例: import yaml class Monster(yaml.YAMLObject): yaml_tag = u'!Monster' ...