標籤:
一.為什麼會出現表單重複提交
1.當使用者在表單中填寫完資訊,點擊提交按鈕後,肯能會因為沒有看到成功資訊而在此點擊提交按鈕,從而導致在伺服器端收到兩條同樣的資訊,如果這個資訊要儲存到資料庫中的,那麼就會出現兩條重複的資料,或者可能出現資料庫操作異常。
2.當使用者填寫表單資訊完成後,點擊表單提交,即使響應及時,也有可能會出現表單重複提交的情況。一般伺服器端的程式在處理完使用者提交的資訊後,調用的是Request.Dispatcher.forward()方法將使用者的請求導向成功頁面,使用者看到成功資訊後,點擊重新整理,此時瀏覽器將再次提交使用者先前輸入的資料,剛才說了這是因為調用Request.Dispatcher.forward()方法返回成功頁面的,瀏覽器鎖保留的url是先前表單提交的url,如果採用的是HttpServletResponse.sendRedirect()方法將用戶端重新導向到成功頁面,就不會出現重複提交的問題了。
二.避免表單重複提交的原理
避免表單重複提交有兩種方案,一種是在JavaScript指令碼上,第二種是在伺服器端來阻止表單重複提交,我們主要那麼這裡我們主要針對的是伺服器端來處理表單的重複提交.
1.用訪問包含表單的頁面,伺服器端在這次會話中,建立一個session對象,併產生一個令牌值,將這個令牌值作為隱藏輸入欄位的值,隨表單一起發送到用戶端,同事將令牌值儲存到session中。
2.使用者提交頁面,伺服器端首先判斷請求參數中的令牌值和Session中儲存到額令牌值是否相等,如果相等,則清楚Session中的令牌值,然後執行資料吃了操作,如果不相等,則提示使用者已經提交過表單了,同時產生一個新的令牌值,儲存到Session中,當使用者重新訪問提交資料頁面時,將新產生的令牌值作為隱藏輸入欄位的值。
三.使用Struts2來實現防止表單重複提交
Struts2使攔截器來檢查表單是否重複提交,他也是採用同步令牌的方式來實現對錶單重複提交的判斷。
第一步:
首先要在表中使用<s:token>標籤,並指定一二令牌的名字,<s:token>標籤用來建立一個新的令牌值,並用你所指定的令牌名把令牌值儲存到Session中,這個令牌值是隨機產生的經過加密的字元序列。
從中可以看出,<s:token>標籤會在表單中產生兩個隱藏欄位。第一個隱藏欄位的名字是固定的,struts.token.name.第二個隱藏欄位的名字是<s:token>標籤name屬性的值,他的值就是隨機產生的經過加密的令牌值。伺服器端的攔截器首先根據struts.token.name請求參數找到儲存了令牌值的請求參數名user.token,然後在擷取user.token請求參數,得到令牌的值。
第二步:
需要在Action配置引用TokenInterceptor或者TokenSessionStoreInterceptor攔截器,這兩個攔截器已經在struts-defatul.xml中定義,但沒有包含在defaultStatck攔截器中。
我們這裡先使用TokenInterceptor攔截器,當表單提交時,TokenInterceptor攔截器擷取請求,擷取標準的struts.token.name請求參數,得到儲存了令牌值的請求參數名,然後再根據這個請求的參數擷取令牌值,接著TokenInterceptor根據剛才得到的令牌名,從session中取出<s:token>標籤先前儲存到session中的令牌值,對兩個令牌值進行比較。如果session中的令牌值等於請求參數中的令牌值,那麼刪除session中的令牌值,並調用handleValidToken()方法,該方法直接調用,他首先調用Action的方法對請求進行處理;如果兩個值不相等,那麼handelInvalidToken()方法被調用,它首先添加一個Action層級的錯誤訊息到這個Action(Action需要實現ValidationAware,ActionSupport基類實現了該介面),然後直接返回INVALID_TOKEN_CODE結果碼,從而跳過Action的執行。INVALID_TOKEN_CODE是一個在TokenInterceptor中定義的靜態常量,值為invalid.token
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <!-- 設定檔中只要添加以下配置,那麼以後修改設定檔不用重啟 tomcat --> <constant name="struts.devMode" value="true" /><!--name:常量的名稱 value:常量的值 --> <!--處理中文亂碼問題的解決 --> <!--國際化資訊內碼 --> <constant name="struts.i18n.encodeing" value="UTF-8" /> <package name="default" namespace="/" extends="struts-default"> <action name="token" class="cn.action.RegistAction" > <!-- 配置Token攔截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="token"></interceptor-ref> <!-- 如果重複提交,則跳轉到error.jsp --> <result name="invalid.token">/error.jsp</result> <result name="success">/success.jsp</result> </action> </package></struts>
action:
package cn.action;import com.opensymphony.xwork2.ActionSupport;public class RegistAction extends ActionSupport{ private String name; private String pwd; @Override public String execute() throws Exception { for (int i = 0; i < 5000000; i++) { System.out.println("===="); } return SUCCESS; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }
註冊頁面:
<body>
<s:actionerror/> <s:form action="token"> <s:token name="user.token"></s:token> <s:textfield label="使用者名稱" name="name"></s:textfield> <s:password label="密碼" name="pwd"></s:password> <s:submit value="提交"></s:submit> </s:form> </body>
如果使用者連續提交兩次,便會走造成表單重複提交,會跳到該頁面顯示錯誤資訊。也可以通過配置來該錯誤提示資訊。
避免表單重複提交與等待頁面