一開始我使用了 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" onsubmit="return checkSubmit();"> 2 還是javascript,將提交按鈕或者image置為disable
- <html:form action="myAction.do" method="post"
- onsubmit="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);
- }
- }
|