`

防止用户重复提交的方法

 
阅读更多

表单重复提交是在多用户Web应用中最常见、带来很多麻烦的一个问题。有很多的应用场景都会遇到重复提交问题,比如:

点击提交按钮两次。 点击刷新按钮。 使用浏览器后退按钮重复之前的操作,导致重复提交表单。 使用浏览器历史记录重复提交表单。 浏览器重复的HTTP请求。

  几种防止表单重复提交的方法

  1.禁掉提交按钮。表单提交后使用Javascript使提交按钮disable。这种方法防止心急的用户多次点击按钮。但有个问题,如果客户端把Javascript给禁止掉,这种方法就无效了。

  我之前的文章曾说过用一些Jquery插件效果不错。

  2.Post/Redirect/Get模式。在提交后执行页面重定向,这就是所谓的Post-Redirect-Get (PRG)模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。

  这能避免用户按F5导致的重复提交,而其也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退按导致的同样问题。

  3.在session中存放一个特殊标志。当表单页面被请求时,生成一个特殊的字符标志串,存在session中,同时放在表单的隐藏域里。接受处理表单数据时,检查标识字串是否存在,并立即从session中删除它,然后正常处理数据。

  如果发现表单提交里没有有效的标志串,这说明表单已经被提交过了,忽略这次提交。

  这使你的web应用有了更高级的XSRF保护。

  4.在数据库里添加约束。在数据库里添加唯一约束或创建唯一索引,防止出现重复数据。这是最有效的防止重复提交数据的方法。

 

----------------------------------

spring mvc 防止重复提交表单的两种方法,推荐第二种

第一种方法:判断session中保存的token

原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过。
 

1.新建注解:

 

/**
 * <p>
 * 防止重复提交注解,用于方法上<br/>
 * 在新建页面方法上,设置needSaveToken()为true,此时拦截器会在Session中保存一个token,
 * 同时需要在新建的页面中添加
 * <input type="hidden" name="token" value="${token}">
 * <br/>
 * 保存方法需要验证重复提交的,设置needRemoveToken为true
 * 此时会在拦截器中验证是否重复提交
 * </p>
 * @author: chuanli
 * @date: 2013-6-27上午11:14:02
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidDuplicateSubmission {
    boolean needSaveToken() default false;
    boolean needRemoveToken() default false;
}

 

 

2. 新建拦截器

 

/**
 * <p>
 * 防止重复提交过滤器
 * </p>
 *
 * @author: chuanli
 * @date: 2013-6-27上午11:19:05
 */
public classAvoidDuplicateSubmissionInterceptorextendsHandlerInterceptorAdapter{
    private static final Logger LOG = Logger.getLogger(AvoidDuplicateSubmissionInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        User user = UserUtil.getUser();
        if (user != null) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();

            AvoidDuplicateSubmission annotation = method.getAnnotation(AvoidDuplicateSubmission.class);
            if (annotation != null) {
                boolean needSaveSession = annotation.needSaveToken();
                if (needSaveSession) {
                    request.getSession(false).setAttribute("token", TokenProcessor.getInstance().generateToken());
                }

                boolean needRemoveSession = annotation.needRemoveToken();
                if (needRemoveSession) {
                    if (isRepeatSubmit(request)) {
                        LOG.warn("please don't repeat submit,[user:" + user.getUsername() + ",url:"
                                + request.getServletPath() + "]");
                        return false;
                    }
                    request.getSession(false).removeAttribute("token");
                }
            }
        }
        return true;
    }

    private boolean isRepeatSubmit(HttpServletRequest request) {
        String serverToken = (String) request.getSession(false).getAttribute("token");
        if (serverToken == null) {
            return true;
        }
        String clinetToken = request.getParameter("token");
        if (clinetToken == null) {
            return true;
        }
        if (!serverToken.equals(clinetToken)) {
            return true;
        }
        return false;
    }

}

 

 

3. 在Spring中配置

 

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
   <propertyname="interceptors"><list><beanclass="com.sohu.tv.crm.aop.UserLogInterceptor"/><beanclass="com.sohu.tv.crm.aop.AvoidDuplicateSubmissionInterceptor"/></list></property></bean>

 

 

4. 在相关方法中加入注解:

 

@RequestMapping("/save")
 @AvoidDuplicateSubmission(needRemoveToken = true)
    public synchronized ModelAndView save(ExecutionUnit unit, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

@RequestMapping("/edit")
    @AvoidDuplicateSubmission(needSaveToken = true)
    public ModelAndView edit(Integer id, HttpServletRequest request) throws Exception {

 

5.在新建页面中加入
                <input type="hidden" name="token" value="${token}">
注意在ajax提交时 要加上 formToken参数

第二种方法(判断请求url和数据是否和上一次相同)

推荐,非常简单,页面不需要任何传入,只需要在验证的controller方法上写上自定义注解即可

写好自定义注解

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.thinkgem.jeesite.common.repeat_form_validator;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. /** 
  9.  * 一个用户 相同url 同时提交 相同数据 验证 
  10.  * @author Administrator 
  11.  * 
  12.  */  
  13. @Target(ElementType.METHOD)  
  14. @Retention(RetentionPolicy.RUNTIME)  
  15. public @interface SameUrlData {  
  16.   
  17.       
  18. }  



 

写好拦截器

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.thinkgem.jeesite.common.repeat_form_validator;  
  2.   
  3. import java.lang.reflect.Method;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import org.springframework.web.method.HandlerMethod;  
  11. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
  12.   
  13. import com.thinkgem.jeesite.common.mapper.JsonMapper;  
  14.   
  15. /** 
  16.  * 一个用户 相同url 同时提交 相同数据 验证 
  17.  * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单 
  18.  * @author Administrator 
  19.  * 
  20.  */  
  21. public class SameUrlDataInterceptor  extends HandlerInterceptorAdapter{  
  22.       
  23.       @Override  
  24.         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
  25.             if (handler instanceof HandlerMethod) {  
  26.                 HandlerMethod handlerMethod = (HandlerMethod) handler;  
  27.                 Method method = handlerMethod.getMethod();  
  28.                 SameUrlData annotation = method.getAnnotation(SameUrlData.class);  
  29.                 if (annotation != null) {  
  30.                     if(repeatDataValidator(request))//如果重复相同数据  
  31.                         return false;  
  32.                     else   
  33.                         return true;  
  34.                 }  
  35.                 return true;  
  36.             } else {  
  37.                 return super.preHandle(request, response, handler);  
  38.             }  
  39.         }  
  40.     /** 
  41.      * 验证同一个url数据是否相同提交  ,相同返回true 
  42.      * @param httpServletRequest 
  43.      * @return 
  44.      */  
  45.     public boolean repeatDataValidator(HttpServletRequest httpServletRequest)  
  46.     {  
  47.         String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());  
  48.         String url=httpServletRequest.getRequestURI();  
  49.         Map<String,String> map=new HashMap<String,String>();  
  50.         map.put(url, params);  
  51.         String nowUrlParams=map.toString();//  
  52.           
  53.         Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");  
  54.         if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面  
  55.         {  
  56.             httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);  
  57.             return false;  
  58.         }  
  59.         else//否则,已经访问过页面  
  60.         {  
  61.             if(preUrlParams.toString().equals(nowUrlParams))//如果上次url+数据和本次url+数据相同,则表示城府添加数据  
  62.             {  
  63.                   
  64.                 return true;  
  65.             }  
  66.             else//如果上次 url+数据 和本次url加数据不同,则不是重复提交  
  67.             {  
  68.                 httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);  
  69.                 return false;  
  70.             }  
  71.               
  72.         }  
  73.     }  
  74.   
  75. }  



 

配置spring mvc

 

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <mvc:interceptor>  
  2.            <mvc:mapping path="/**"/>  
  3.            <bean class="com.thinkgem.jeesite.common.repeat_form_validator.SameUrlDataInterceptor"/>  
  4.        </mvc:interceptor>  

 

分享到:
评论

相关推荐

    spring boot 防止重复提交实现方法详解

    Spring Boot 防止重复提交实现方法详解 Spring Boot 防止重复提交是指在用户提交表单或请求时,防止同一客户端在短时间内对同一 URL 的重复提交,从而避免服务器端的处理压力和数据的一致性问题。下面将详细介绍 ...

    asp.net 页面防止重复提交

    然而,这种方法并不能完全防止所有情况下的重复提交,因为某些用户可能使用浏览器的刷新功能或者在网络延迟后多次点击。 ASP.NET MVC框架提供了一些内置机制来处理此问题。例如,可以使用`AntiForgeryToken`辅助...

    element-ui如何防止重复提交的方法步骤

    在IT行业中,尤其是在前端开发领域,防止用户重复提交是一项重要的任务,这有助于避免因网络延迟或用户误操作导致的数据混乱。Element-UI,一个流行的Vue.js组件库,提供了多种方式来处理这个问题。以下是如何在使用...

    防止页面刷新重复提交的方法.

    防止页面刷新重复提交的方法 防止页面刷新重复提交是 Web 开发中常见的问题,多次提交表单可能会导致不必要的数据重复录入、服务器压力增大等问题。下面我们将详细介绍防止页面刷新重复提交的方法。 一、验证码...

    防止Layui form表单重复提交的实现方法

    Layui是一种基于jQuery的前端UI框架,它提供了一套丰富的界面元素和组件,广泛...通过上述方法,可以有效地防止用户在表单提交过程中产生的重复提交行为,提升用户的操作体验,确保数据提交的正确性和服务器的稳定性。

    javascript方式防止表单重复提交

    JavaScript作为客户端脚本语言,可以通过多种策略来防止用户意外或恶意地多次提交表单。以下是一些关键的知识点: 1. **禁用提交按钮**:最简单的预防方法是在用户点击提交按钮后立即将其禁用。这可以通过监听`...

    防止用户重复提交表单的方法和组件.rar

    好友使用vue技术封装了一个专门用于提交表单和下载文件的“防抖按钮”,其实现原理和使用方法看这里 https://blog.csdn.net/PursueExcellence/article/details/103903139。

    防止表单重复提交(asp.net )

    2. **防止表单重复提交的方法**: - **服务器端验证**: - 使用`Session`或`Viewstate`来记录用户是否已经提交过表单。一旦表单提交成功,将一个标识存储在会话或视图状态中,后续的提交请求检查该标识,若存在则...

    springboot2.1+redis+拦截器 防止表单重复提交

    在现代Web应用开发中,防止表单重复提交是一项重要的任务,因为这可能导致数据不一致性和服务器资源浪费。本文将深入探讨如何使用Spring Boot 2.1、Redis和拦截器来实现这一功能。以下是对这个主题的详细解释: ...

    防止页面重复提交demo

    这种方法可以防止因用户刷新页面而导致的重复提交。 在具体实现中,以下是一些关键步骤: 1. **生成token**:在用户打开表单页面时,服务器生成一个唯一的随机字符串,存储在session中,并将其作为隐藏字段包含在...

    ASP.NET中防止刷新页面造成表单重复提交

    ### ASP.NET中防止刷新页面...通过上述方法,可以在不影响用户体验的前提下有效地防止表单重复提交,从而提高系统的稳定性和安全性。这种方法适用于大多数Web应用场合,特别是那些对数据准确性和一致性要求较高的场景。

    防止表单重复提交

    1. **客户端验证**:在JavaScript中,可以监听表单提交事件,一旦表单提交,禁用提交按钮,防止用户再次点击。但这种方法并不完全可靠,因为JavaScript可以被禁用,或者恶意用户可能绕过这个限制。 2. **服务器端...

    修改禁止多次重复提交

    在IT行业中,尤其是在Web开发领域,防止用户多次重复提交数据是一项重要的任务,这可以避免数据库出现冗余数据,保持系统稳定。"修改禁止多次重复提交"这个话题涉及到前端交互、后端处理以及数据库操作等多个层面。...

    ajax 防止按钮重复提交

    通过以上方法,我们能够在一定程度上避免由于用户重复点击导致的数据重复提交问题。这种方式不仅能够提升用户体验,还能有效减轻服务器的负担。在实际项目中,开发者还可以根据需求添加更多的异常处理逻辑,使得程序...

    防止用户刷新,重复提交数据

    在Web开发中,防止用户刷新页面而导致重复提交数据是一个重要的问题。这通常涉及到表单提交、支付确认等关键操作,确保这些操作仅执行一次是非常必要的。本资源提供了一个解决方案,通过使用“Token”机制来避免这种...

    [Jsp]防止页面表单重复提交的解决方法

    二、防止表单重复提交的方法 1. **使用JavaScript禁用提交按钮** 在表单提交时,可以使用JavaScript来禁用提交按钮,以防止用户连续点击。例如: ```javascript function disableSubmit() { document....

    自定义标签 防止重复提交

    在Web开发中,防止用户重复提交是常见的需求,特别是在数据敏感的操作中,如订单确认、用户注册等。自定义标签是一种优雅的解决方法,它能够有效地控制页面的行为,避免因为用户误操作或网络延迟导致的数据重复插入...

    Struts2防止重复提交解决方案

    防止重复提交的主要原因是服务器处理时间过长或用户误操作。用户点击提交按钮后,如果服务器响应慢,他们可能会再次点击,导致相同请求的多次提交。另一种情况是服务器使用forward方式跳转,用户刷新页面时,数据会...

    解析php防止form重复提交的方法

    总之,防止表单重复提交的方法可以分为客户端和服务器端两个层面。通过组合使用JavaScript和PHP,可以较好地防止用户无意或有意地多次提交表单,从而保证Web应用的稳定性和数据的准确性。在实现时,开发者应当选择...

Global site tag (gtag.js) - Google Analytics