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

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

比较麻烦,每次在提交表单时都必须传入上次的token。而且当一个页面使用ajax时,多个表单提交就会有问题。

注解Token代码:

package com.thinkgem.jeesite.common.repeat_form_validator;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 页面form   token
 * @author Administrator
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FormToken {

    boolean save() default false;

    boolean remove() default false;
}

拦截器TokenInterceptor代码:

package com.thinkgem.jeesite.common.repeat_form_validator;

import java.lang.reflect.Method;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class FormTokenInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            FormToken annotation = method.getAnnotation(FormToken.class);
            if (annotation != null) {
                boolean needSaveSession = annotation.save();
                if (needSaveSession) {
                    request.getSession(false).setAttribute("formToken", UUID.randomUUID().toString());
                }
                boolean needRemoveSession = annotation.remove();
                if (needRemoveSession) {
                    if (isRepeatSubmit(request)) {
                        return false;
                    }
                    request.getSession(false).removeAttribute("formToken");
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

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

然后在Spring MVC的配置文件里加入:

<mvc:interceptors>
	<mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.thinkgem.jeesite.common.repeat_form_validator.FormTokenInterceptor"/>
        </mvc:interceptor>
	</mvc:interceptors>

相关代码已经注释,相信你能看懂。
关于这个方法的用法是:在需要生成token的controller上增加@FormToken(save=true),而在需要检查重复提交的controller上添加@FormToken(remove=true)就可以了。
另外,你需要在view里在form里增加下面代码:

<inputtype="hidden"name="formToken"value="${formToken}" />

已经完成了,去试试看你的数据还能重复提交了吧。

注意在ajax提交时 要加上 formToken参数

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

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

写好自定义注解

package com.thinkgem.jeesite.common.repeat_form_validator;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 一个用户 相同url 同时提交 相同数据 验证
 * @author Administrator
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SameUrlData {

}

写好拦截器

package com.thinkgem.jeesite.common.repeat_form_validator;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.thinkgem.jeesite.common.mapper.JsonMapper;

/**
 * 一个用户 相同url 同时提交 相同数据 验证
 * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单
 * @author Administrator
 *
 */
public class SameUrlDataInterceptor  extends HandlerInterceptorAdapter{

	  @Override
	    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
	        if (handler instanceof HandlerMethod) {
	            HandlerMethod handlerMethod = (HandlerMethod) handler;
	            Method method = handlerMethod.getMethod();
	            SameUrlData annotation = method.getAnnotation(SameUrlData.class);
	            if (annotation != null) {
	            	if(repeatDataValidator(request))//如果重复相同数据
	            		return false;
	            	else
	            		return true;
	            }
	            return true;
	        } else {
	            return super.preHandle(request, response, handler);
	        }
	    }
	/**
	 * 验证同一个url数据是否相同提交  ,相同返回true
	 * @param httpServletRequest
	 * @return
	 */
	public boolean repeatDataValidator(HttpServletRequest httpServletRequest)
	{
		String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());
		String url=httpServletRequest.getRequestURI();
		Map<String,String> map=new HashMap<String,String>();
		map.put(url, params);
		String nowUrlParams=map.toString();//

		Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");
		if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面
		{
			httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
			return false;
		}
		else//否则,已经访问过页面
		{
			if(preUrlParams.toString().equals(nowUrlParams))//如果上次url+数据和本次url+数据相同,则表示城府添加数据
			{

				return true;
			}
			else//如果上次 url+数据 和本次url加数据不同,则不是重复提交
			{
				httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
				return false;
			}

		}
	}

}

配置spring mvc

 <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.thinkgem.jeesite.common.repeat_form_validator.SameUrlDataInterceptor"/>
        </mvc:interceptor>
时间: 2024-09-28 23:07:14

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

spring mvc 数据绑定问题 提交表单提示HTTP status 400, The request sent by the client was syntactically incorrect

我们在spring mvc 中controller方法中的参数,spring mvc会自动为我们进行数据绑定. spring mvc 方法中不一定要全部都有 form表单提交的属性, 也可以有 请求属性中 没有的参数(这时候只会把对应不上的参数设为null),这两种情况都不会报错. 但是有几种情况会报错,可能会提示HTTP status 400,  The request sent by the client was syntactically incorrect,而且此时如果加断点你会发现根本

asp.net 防止用户通过后退按钮重复提交表单_实用技巧

防止用户通过后退按钮重复提交表单 <% response.Buffer=true response.Expires=0 response.ExpiresAbsolute=now()-1 response.CacheControl="no-cache" %> response.Buffer=true的意思就是指明输出页面是否被缓冲,当属性值为True时,服务器将不会向客户端发送任何信息,直到所有程序执行完或者遇到 <% Response.Flush %>或<

PHP防止用户重复提交表单

我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦. 那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手: 首先从前端做限制.前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效. 第二,我们可以在提交后做redirect页面重定向,即提交后跳

php防止用户重复提交表单_php技巧

我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦. 效果图:   那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手: 首先从前端做限制.前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效. 第二,我们可以在提交后做redirect页面重定

php判断客户端IP来防止重复提交表单的方法

本文实例分析了php通过记录IP来防止表单重复提交方法.分享给大家供大家参考.具体分析如下: 这个原理比较的简单就是用户第一次提交时我们记录提交用户的IP地址,这样如果用户在固定时间内再次提交表单就会提示重复提交了,这种做法通常用于在顶一下,支持一下这种应用中了,在防止数据重复提交是一个非常不好的选择. 例子,代码如下:  代码如下 复制代码 <?php  session_start(); if(empty($_SESSION['ip']))//第一次写入操作,判断是否记录了IP地址,以此知道是

PHP防止重复提交表单的例子

我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦. 那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手,首先从前端做限制.前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效.第二,我们可以在提交后做redirect页面重定向,即提交后跳转到

php+html5使用FormData对象提交表单及上传图片的方法

 这篇文章主要介绍了php+html5使用FormData对象提交表单及上传图片的方法,实例分析了FormData对象的使用技巧,非常具有实用价值,需要的朋友可以参考下     本文实例讲述了php+html5使用FormData对象提交表单及上传图片的方法.分享给大家供大家参考.具体分析如下: FormData 对象,可以把form中所有表单元素的name与value组成一个queryString,提交到后台.在使用Ajax提交时,使用FormData对象可以减少拼接queryString的工

php+html5使用FormData对象提交表单及上传图片的方法_php技巧

本文实例讲述了php+html5使用FormData对象提交表单及上传图片的方法.分享给大家供大家参考.具体分析如下: FormData 对象,可以把form中所有表单元素的name与value组成一个queryString,提交到后台.在使用Ajax提交时,使用FormData对象可以减少拼接queryString的工作量. 使用FormData对象 1.创建一个FormData空对象,然后使用append方法添加key/value 复制代码 代码如下: var formdata = new

Chrome Form多次提交表单问题的解决方法_javascript技巧

今天用chrome提交一个表单时,发现一个奇怪的问题: 复制代码 代码如下: //提交表单 document.frmOrder.action = 'http://www.abc.com/d.aspx'; document.frmOrder.method = 'POST'; document.frmOrder.target = '_blank'; document.frmOrder.submit(); 第一次提交可以,第二次提交就没有任何响应了.需要重新加载页面后才可以提交,而这个问题在Firef