用戶重複提交同一個HTML表單的原因不在乎兩種:一是操作失誤;二是某個表單的處理時間過長而使得用戶不知該如何是好。在某些場合,重複提交同一個HTML表單的後果可能非常嚴重;在另外一些場合,這種情況也許只會令人敢不快而已。例如,在使用使用卡進行在線支付到時候,如果服務器的響應速度太慢,用戶難免會再次點擊提交按鈕,而這就有可能導致那張信用卡上的金額被划走兩次。我們再來看一個後果沒那麼嚴重的例子 -- 用來錄入產品信息的表單,重複提交這些表單可能同一中產品被添加二次。
在防止重複提交同一個表單方面,不同的瀏覽器有這不同的行爲。Mozilla Firefox瀏覽器對重複點擊同一按鈕將不予理睬,這爲我們提供了某種形式的保護。其他品牌的瀏覽器,包括IE在內,目前還沒有實現能夠防止重複提交的功能。此外,Mozilla和非Mozilla瀏覽器都算上,如果在請求被處理之後按下了瀏覽器本身的Refresh/Reload(刷新)按鈕。同樣的請求就會被再次提交,而這顯然是一種重複提交行爲。因爲,質押重複提交有可能給你的業務邏輯帶來不良影響,你就必須採取必要的預防措施。
Struts已經內置了能夠防止用戶重複提交同一個HTML表單的功能。它採用的辦法在其他一些用來開發Web應用程序的技術裏也可以見到:讓服務器生成一個唯一標記,並在服務器和表單裏保存一份這個標記的副本。此後,在用戶提交表單的時候,表單裏的標記將雖說這其他請求參數一起發送到服務器,服務器將對它收到的標記和它留存的標記進行比較。如果兩者匹配,這次從提交來的表單就是被認爲是有效的,服務器將對之做出必要的處理並重新設置一個標記。隨後(因爲不小心)提交相同的表單就會失敗,因爲服務器上的標記已經重置。
1,struts2的防止重複提交,也使用到了token(令牌機制),並且使用到了struts2的一個叫token的攔截器
添加商品頁面:
- <body>
- <s:form action="product_doAddProduct.action" method="post">
- <s:token></s:token>
- <s:textfield name="name" label="商品名稱"></s:textfield>
- <s:textfield name="price" label="商品價格"></s:textfield>
- <s:submit value="提交"></s:submit>
- </s:form>
- </body>
struts.xml 配置文件
- <package name="token" extends="struts-default" namespace="/jsp">
- <action name="product_*" class="org.cric.action.ProductAction" method="{1}">
- <result name="success">/jsp/product.jsp</result>
- <result name="invalid.token">/jsp/error.jsp?message=重複提交</result>
- <interceptor-ref name="token"/>
- <span style="white-space: pre;"> </span><interceptor-ref name="defaultStack"/>
- </action>
- </package>
動作層:
- public String doAddProduct() throws Exception{
- System.out.println("添加商品了……");
- Thread.sleep(10000);
- return "success";
- }
錯誤頁面:
- <body>
- ${param['message']}
- </body>
顯示商品信息頁面:
- <body>
- 商品名稱:<s:property value="%{name}"/><br>
- 商品價格:<s:property value="%{price}"/>
- </body>
注意:
a:當攔截器攔截到 當發生重複提交的action時候,會跳轉到invalid.token指定的頁面。
b:爲了使用同一的錯誤頁面,在錯誤頁面上接受到message參數的值,可以在error.jsp使用 ${param['message']}
c:在提交頁面的form中添加<s:token/>標籤,需要在頁面中加上。
2,struts2的防止重複提交,也使用到了token(令牌機制),並且使用到了struts2的一個叫token-session的攔截器
Token Session攔截器擴展了Token並提供了一種更復雜的服務。Token Session攔截器不想Token攔截器那樣會返回一種特殊的結果並添加一個動作錯誤,它採用的做法只是阻斷後續的提交,而這麼做的後果是用戶將看到同一的響應,就好像只有一次提交那樣!
- <package name="token" extends="struts-default" namespace="/jsp">
- <action name="product_*" class="org.cric.action.ProductAction" method="{1}">
- <result name="success">/jsp/product.jsp</result>
- <interceptor-ref name="token-session">
- <param name="includeMethods">doAddProduct</param>
- </interceptor-ref>
- <interceptor-ref name="defaultStack"/>
- </action>
- </package>
注意:
a:includeMethods 指定需要攔截的方法 excludeMethods 指定不需要攔截的方法,多個方法使用逗號分隔
b:把第一個程序的配置文件換成這個,不需要錯誤頁面。