一开始我使用了
this.button_OK.Attributes.Add("onclick", "window.document.getElementById(’" + this.Button_OK.ClientID + "’).disabled = true;")
但这样做的结果是server端的button click处理函数不会被执行.
正确的做法是在Page Load中添加代码:
//.net 2.0
string script = ClientScript.GetPostBackEventReference(this.Button_OK, null);
if (!Page.IsPostBack)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("window.document.getElementById(’" + this.Button_OK.ClientID + "’).disabled = true;");
sb.Append(script);
sb.Append(";");
this.Button_OK.Attributes.Add("onclick", sb.ToString());
}
// .net 1.0
string script = this.GetPostBackEventReference(this.button_OK);
If (!Page.IsPostBack)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("window.document.getElementById(’" + this.button_OK.ClientID + "’).disabled = true;");
sb.Append(script);
sb.Append(";")
this.button_OK.Attributes.Add("onclick", sb.ToString());
}
GetPostBackEventReference会生成html代码:
<script type="text/javascript">
<!–
var theForm = document.forms[’form1′];
if (!theForm)
{
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// –>
</script>
生成的script值为__doPostBack(’Button_OK’,'’)
------------------------------------------------------------------------------
xwork.xml 的配置:
这个拦截器可以保证一个令牌对应一个请求。确保后退按钮和两次提交不会产生不希望的效果。 例如你可以使用这个来防止粗心的用户在在线商店点了两下"结帐"按钮。这个拦截器使用了非常简单的机制来处理非法令牌:返回一个invliad.token的结果,这样你就可以在action配置中做映射了。一个复杂一些的实现是TokenSessionStoreInterceptor, 可以在发现非法令牌时提供更好的处理逻辑。
注意: 为了设置表单的令牌,你必须使用token标签。 这个标签放在表单中,并且这个表单是提交到受这个拦截器保护的action:任何不提供令牌(使用token标签产生的)的请求将被处理为非法请求
国际化注意事项:这个拦截器用下面的键作为错误信息。
注意: 因为这个拦截器是扩展于MethodFilterInterceptor, 所以可以决定在action中的哪些方法上应用它。
<action name="someAction" class="com.examples.SomeAction">
<interceptor-ref name="token"/>
<interceptor-ref name="basicStack"/>
<result name="success">good_result.ftl</result>
</action>
<-- 在这个例子中,action的myMethod方法不会做令牌检查 -->
<action name="someAction" class="com.examples.SomeAction">
<interceptor-ref name="token">
<param name="excludeMethods">myMethod</param>
</interceptor-ref name="token"/>
<interceptor-ref name="basicStack"/>
<result name="success">good_result.ftl</result>
</action>
表单的配置 :
<ww:token />
防止多次提交表单.
使用token标签能帮助解决多次提交表单的问题.此标签需要你启用TokenInterceptor 或者TokenSessionInterceptor拦截器.
ww:token标签只不过放置了一个隐藏的表单元素,它包含一个唯一的令牌.
例子:
<form name="demoForm" action="someAction.action" method="Post">
<ww:token />
</form>
----------------------------------------------------------------------------------------
Web应用中避免Form重复提交的三种方案
前两种是利用javascript,后面一种是在使用Struts的情况下的参考实现
- 1 javascript ,设置一个变量,只允许提交一次。
-
- <script language="javascript">
- var checkSubmitFlg = false;
- function checkSubmit() {
- if (checkSubmitFlg == true) {
- return false;
- }
- checkSubmitFlg = true;
- return true;
- }
- document.ondblclick = function docondblclick() {
- window.event.returnValue = false;
- }
- document.onclick = function doconclick() {
- if (checkSubmitFlg) {
- window.event.returnValue = false;
- }
- }
- </script>
<html:form action="myAction.do" method="post" οnsubmit="return checkSubmit();">
- 2 还是javascript,将提交按钮或者image置为disable
-
- <html:form action="myAction.do" method="post"
- οnsubmit="getElById('submitInput').disabled = true; return true;">
-
- <html:image styleId="submitInput" src="images/ok_b.gif" border="0" />
-
- </html:form>
-
- 3 利用struts的同步令牌机制
利用同步令牌(Token)机制来解决Web应用中重复提交的问题,Struts也给出了一个参考实现。
基本原理:
服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,
看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给
客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次
提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
-
- if (isTokenValid(request, true)) {
- // your code here
- return mapping.findForward("success");
- } else {
- saveToken(request);
- return mapping.findForward("submitagain");
- }
Struts根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考
TokenProcessor类中的generateToken()方法。
1. //验证事务控制令牌,<html:form >会自动根据session中标识生成一个隐含input代表令牌,防止两次提交
2. 在action中:
-
- //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"
- // value="6aa35341f25184fd996c4c918255c3ae">
- if (!isTokenValid(request))
- errors.add(ActionErrors.GLOBAL_ERROR,
- new ActionError("error.transaction.token"));
- resetToken(request); //删除session中的令牌
3. action有这样的一个方法生成令牌
-
- protected String generateToken(HttpServletRequest request) {
-
- HttpSession session = request.getSession();
- try {
- byte id[] = session.getId().getBytes();
- byte now[] =
- new Long(System.currentTimeMillis()).toString().getBytes();
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(id);
- md.update(now);
- return (toHex(md.digest()));
- } catch (IllegalStateException e) {
- return (null);
- } catch (NoSuchAlgorithmException e) {
- return (null);
- }
- }