防止重复提交的各种用法 分享

时间:2025-04-05 08:31:51
防止重复提交的各种用法

用JavaScript防止重复提交表单form的两种方法。
1、用javascript设置一个变量,只允许提交一次。
<script type="text/javascript">
var checkSubmitFlg = false;
function checkSubmit(){
 if (checkSubmitFlg == true){
return false;
 }
 checkSubmitFlg = true;
 return true;
  }
  =
  function docondblclick(){
= false;
  }
  =
  function doconclick(){
  if (checkSubmitFlg){
= false;
  }
}
</script>
<form action="" method="post" οnsubmit="return checkSubmit();">

2、用javascript将提交按钮或者img置为disable
<form action="" method="post" οnsubmit="getElById('submitInput').disabled = true;return true;"> 
<img styleId="submitInput" src="images/ok_b.gif" border="0" />
</form>

3

看下struts框架的方法

看下实现原理.................

如果用户对一个html表单多次提交,web应用应该能够判断用户的重复提交行为,并作出相应的处理。

最常见的是新增一条数据,用户已经提交表单并且服务器端已经完成新增成功。此时用户可能有两个误操作:
1.用户通过浏览器的后退功能,返回到录入页面,重复提交(此时浏览器提供回退功能基本上是个邪恶行为)
2.刷新该页面(因为新增成功的提示页面通常是通过请求转发(forward)过来的,所以此操作实际效果通常等同于1)

这样造成的可能结果有:


1.若程序级别和数据库级别限制了重复记录,会提示类似于“xxx字段已存在,请修改后重新保存”的信息
2.若没有此限制,服务器端会再插入一条数据,而这通常不是用户想要的

误操作2和可能结果2的结合就达成了与用户意图相背的结果:服务器端不停地在增加重复记录,用户认为自己只不过是刷新该提示信息页面。

通用的解决思路是:
用户请求录入页面,这个与服务器建立的一次连接过程中,在服务器端①【生成一个session标识,同时返回到客户端一个与此匹配的hidden域】。用户提交了此页面,服务器端首先②【判断此hidden域与session标识是否匹配】,若不匹配,终止保存操作,提示同一表单不能提交两次,同时①【新建一个session标识和hidden域】,返回录入页面;若匹配,执行插入保存操作,同时③【清空(重置reset)session标识】。

Struts正在基于这样的思路在类中提供了内置支持方法:
protected void saveToken(HttpServletRequest request) 配合标签对应于①
protected boolean isTokenValid(HttpServletRequest request) 对应于②
protected void resetToken(HttpServletRequest request) 对应于③

这样我们在写程序的时候,结合Struts的html标签,只要
1.在forward到页面前加一个action执行saveToken(request)操作,或干脆在中写
2.保存前加个判断操作isTokenValid(request)
3.若isTokenValid(request)返回false,执行saveToken(request)操作,返回错误提示页面;true则执行resetToken(request)操作,然后进行实际的保存操作

 

 

SSH系统中怎样解决刷新重复提交

 

 

插入一个数据,从一个jsp页面中,进入的insert,插入成功,跳转倒页面。
提交插入成功之后,显示路径,显示页面。 若这时候刷新,则会重复插入数据。

1、怎样解决这时候的刷新不会重复提交

2、怎样不用js代码,预防浏览器后退,若后退则提示错误或者跳转倒某页。

你可以google下struts的Token机制

同步令牌器


里可以配置跳转时是内部跳还是外部跳


你可以google下struts的Token机制
 

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

struts1和struts2都有token机制,google一下,很多


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


token令牌

或做个中转面页

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

1,页面脚本实现,当提交过一次表单后,将提交按钮变为不可用,就不会再触发写入数据库的操作. 2,解发写入数据库操作的action之后,调用formbean中的resetform方法,将form中的数据库清空,当然提交form中数据库有一定限制时会起作用,允许向数据库写入null时,就不起作用了. 3,解发写入数据库操作的action之后,不再用forward的方法,转发页面请求,直接采用sendridect...


相关文章: 
struts token解决用户重复提交问题详解
struts的重复提交源码分析
IE浏览器重复提交的问题!

推荐圈子: GT-Grid
更多相关推荐 Struts的Token(令牌)机制能够很好的解决表单重复提交的问题,基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。

这时其实也就是两点,第一:你需要在请求中有这个令牌值,请求中的令牌值如何保存,其实就和我们平时在页面中保存一些信息是一样的,通过隐藏字段来保存,保存的形式如: 〈input type="hidden" name="" value="6aa35341f25184fd996c4c918255c3ae"〉,这个value是TokenProcessor类中的generateToken()获得的,是根据当前用户的session id和当前时间的long值来计算的。第二:在客户端提交后,我们要根据判断在请求中包含的值是否和服务器的令牌一致,因为服务器每次提交都会生成新的Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致。下面就以在数据库中插入一条数据来说明如何防止重复提交。

在Action中的add方法中,我们需要将Token值明确的要求保存在页面中,只需增加一条语句:saveToken(request);,如下所示:

public ActionForward add(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

//前面的处理省略

saveToken(request);

return ("add");

}在Action的insert方法中,我们根据表单中的Token值与服务器端的Token值比较,如下所示:

public ActionForward insert(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

if (isTokenValid(request, true)) {

// 表单不是重复提交

//这里是保存数据的代码

} else {

//表单重复提交

saveToken(request);

//其它的处理代码

}

}

其实使用起来很简单,举个最简单、最需要使用这个的例子:

一般控制重复提交主要是用在对数据库操作的控制上,比如插入、更新、删除等,由于更新、删除一般都是通过id来操作(例如:updateXXXById, removeXXXById),所以这类操作控制的意义不是很大(不排除个别现象),重复提交的控制也就主要是在插入时的控制了。

先说一下,我们目前所做项目的情况:

目前的项目是用Struts+Spring+Ibatis,页面用jstl,Struts复杂View层,Spring在Service层提供事务控制,Ibatis是用来代替JDBC,所有页面的访问都不是直接访问jsp,而是访问Structs的Action,再由Action来Forward到一个Jsp,所有针对数据库的操作,比如取数据或修改数据,都是在Action里面完成,所有的Action一般都继承BaseDispatchAction,这个是自己建立的类,目的是为所有的Action做一些统一的控制,在Struts层,对于一个功能,我们一般分为两个Action,一个Action里的功能是不需要调用Struts的验证功能的(常见的方法名称有add,edit,remove,view,list),另一个是需要调用Struts的验证功能的(常见的方法名称有insert,update)。

就拿论坛发贴来说吧,论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤:

1、转到一个新增的页面,在Action里我们一般称为add,例如:

public ActionForward add(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

throws Exception {

//这一句是输出调试信息,表示代码执行到这一段了

(":: action - subject add");

//your code here

//这里保存Token值

saveToken(request);

//跳转到add页面,在里面定义,例如,跳转到

return ("add");

}

2、在填写标题和内容后,选择 提交 ,会提交到insert方法,在insert方法里判断,是否重复提交了。

public ActionForward insert(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response){

if (isTokenValid(request, true)) {

// 表单不是重复提交

//这里是保存数据的代码

} else {

//表单重复提交

saveToken(request);

//其它的处理代码

}

}

下面更详细一点(注意,下面所有的代码使用全角括号):

1、你想发贴时,点击“我要发贴”链接的代码可以里这样的:

〈html:link action="?method=add"〉我要发贴〈/html:link〉

和 method 这些在如何定义我就不说了,点击链接后,会执行的add方法,代码如上面说的,跳转到页面。页面的代码大概如下:

〈html:form action="?method=insert"〉

〈html:text property="title" /〉

〈html:textarea property="content" /〉

〈html:submit property="发表" /〉

〈html:reset property="重填" /〉

〈html:form〉

如果你在add方法里加了“saveToken(request);”这一句,那在生成的页面上,会多一个隐藏字段,类似于这样〈input type="hidden" name="" value="6aa35341f25184fd996c4c918255c3ae"〉,

2、点击发表后,表单提交到里的insert方法后,你在insert方法里要将表单的数据插入到数据库中,如果没有进行重复提交的控制,那么每点击一次浏览器的刷新按钮,都会在数据库中插入一条相同的记录,增加下面的代码,你就可以控制用户的重复提交了。

if (isTokenValid(request, true)) {

// 表单不是重复提交

//这里是保存数据的代码

} else {

//表单重复提交

saveToken(request);

//其它的处理代码

}

注意,你必须在add方法里使用了saveToken(request),你才能在insert里判断,否则,你每次保存操作都是重复提交。

记住一点,Struts在你每次访问Action的时候,都会产生一个令牌,保存在你的Session里面,如果你在Action里的函数里面,使用了saveToken(request);,那么这个令牌也会保存在这个Action所Forward到的jsp所生成的静态页面里。

如果你在你Action的方法里使用了isTokenValid,那么Struts会将你从你的request里面去获取这个令牌值,然后和Session里的令牌值做比较,如果两者相等,就不是重复提交,如果不相等,就是重复提交了。

由于我们项目的所有Action都是继承自BaseDispatchAction这个类,所以我们基本上都是在这个类里面做了表单重复提交的控制,默认是控制add方法和insert方法,如果需要控制其它的方法,就自己手动写上面这些代码,否则是不需要手写的,控制的代码如下:

public abstract class BaseDispatchAction extends BaseAction {

protected ActionForward perform(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response)

throws Exception {

String parameter = ();

String name = (parameter);

if (null == name) { //如果没有指定 method ,则默认为 list

name = "list";

}

if ("add".equals(name)) {

if ("add".equals(name)) {

saveToken(request);

}

} else if ("insert".equals(name)) {

if (!isTokenValid(request, true)) {

resetToken(request);

saveError(request, new ActionMessage(""));

("重复提交!");

return ("error");

}

}

return dispatchMethod2(mapping, form, request, response, name);

}

}

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

struts的Token机制

-token令牌

做个中转面页好像似乎比较繁琐,感觉ssh系统中到处都要写代码整合,在多做中专页面,感觉又多个麻烦。

 


除了用token之外,你跳转的时候不要用转发,用重定向

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


添加完之后重定向到一个显示的Action中

 

 


Struts 的 Token 机制可以解决这个问题。

1. ? 防止通过超链接重复访问 Struts Action 。

如果我们要防止 A 的默认页面 J 中指向 K 的超链接重复提交数据,按照下列步骤即可:

a. ? 如果 J 是从 Struts Action 转发而来,我们要在该 Struts Action 的 execute 方法中添加下面的一行:

??? saveToken(request);

b. ? 如果 J 不是从 Struts Action 转发而来,那么新建一个 Struts Action ,在该 Struts Action 的 excute 方法中增加上面的一行,然后再从该 action 转到 J 页面。

c. ? 在 J 页面中使用 Struts 标签生成指向 K 的超链接,如:

?? <html:link action="/deleteLayoutAction?layoutId=0" transaction="true" >delete</html:link>

?? 注意红色字体部分。

d. ? 在 <html:link> 标签指向的 action 的 excute 方法中加入下面的代码:

?? if (!isTokenValid(request)) {

???????????????????? return (" 这种情况下就是重复提交,转到相应的页面 ");

????????????? }

e . All Done.

2. ? 防止通过表单重复提交数据。

a. ? 如果 J 是从 Struts Action 转发而来,我们要在该 Struts Action 的 execute 方法中添加下面的一行:

??? saveToken(request);

b. ? 如果 J 不是从 Struts Action 转发而来,那么新建一个 Struts Action ,在该 Struts Action 的 excute 方法中增加上面的一行,然后再从该 action 转到 J 页面。

c. ? 在 J 页面中表单 Action 属性指向的 Struts action 的 excute 方法中加入下面的代码:

?? if (!isTokenValid(request)) {

?????????? saveToken(request);

???????????????????? return (" 这种情况下就是重复提交,转到相应的页面 ");

?? saveToken(request);

????????????? }

e . All Done.