Struts2.0 避免重複提交

來源:互聯網
上載者:User

聲明此文章出處:http://blog.163.com/quentin_wjb/blog/
              quentin_wjb的部落格。
雙擊制禦
有些時候一些操作會非常的耗費時間(Long Lived Operation),例如這個資料庫的匯出,表表產生等。有些時候程式的使用者看到很長時間伺服器沒有反應,傾向於多次點擊提交按鈕。這樣恰恰相反,由於重新使伺服器運行相同的長時間操作,反而讓反應時間更慢。

我們如何來制禦這樣的操作呢?
我們能不能在每個頁面產生的時候,自動產生一個特殊的隱藏欄位,這個隱藏欄位具有唯一性。每次向伺服器提交請求的時候,伺服器就記錄下這個隱藏欄位,當在看到有相同的特殊欄位的內容提交時,伺服器認為這是重複提交,將畫面定位到一個特殊的畫面來提示客戶重複提交了資料。

在Struts2中,內容了對雙擊的制禦操作,特殊的隱藏欄位叫做token。

如何在產生頁面的時候產生token欄位?
使用token標籤。
代碼如下:
<s:url id="formUrl" action="longLivedTokenAction"/>
<s:form action="%{formUrl}" method="post">
      <s:token />
      <s:textfield name="name" label="Name"/>
      <s:textfield name="password" label="Password"/>
      <s:submit/>
     
</s:form>
其中<s:token />標籤用來產生一個唯一的隱藏欄位,在啟動並執行時候產生的內容如下:
<input type="hidden" name="struts.token" value="C21ZWHEH0Q4B6FY15ZO5BFM1I9W8SIQH" />

如何在伺服器上記錄已經提交的token?
可以使用token intercepter。
代碼如下:
<action name="longLivedTokenAction" class="com.jpleasure.LongLivedTokenAction">
            <interceptor-ref name="token"/>
            <interceptor-ref name="basicStack"/>
            <result>/jsp/longLived.jsp</result>
            <result name="invalid.token">/jsp/invalidToken.jsp</result>
</action>
上述<interceptor-ref name="token"/>表示所有的請求必須經過token Interceptor,token Interceptor作用就是紀錄所有已經提交的token。那麼發現提交的token被重複提交的時候怎麼辦呢?也許大家已經猜到了,他會重新導向到invalid.token所指向的頁面,也就是/jsp/invalidToken.jsp。

基於Interceptor的執行順序按照struts.xml中定義的順序,為了更早的結束重複提交的處理,應該將Token Interceptor放在所有Interceptor的最面。

有了上述的Token Interceptor,可以防止客戶重複提交,大大地降低了伺服器的負荷。但是對使用者來說,可能會很不方便,一不小心點擊了提交按鈕,進入到了invalid.token頁面,就再也回不去了,上述的操作就再也看不見了。

等待畫面
我們能不能提供一個等待畫面呢?
每次我們提交之後畫面立即遷移到一個類似狀態條的畫面,這個畫面不斷的向伺服器請求,以確定Action是否執行完畢,一旦Action執行完畢,立即定位到正確的畫面。這樣不是更好。

Struts2也提供了對等待畫面的支援。
首先當我們提交完成的時候,畫面會前一到一個叫做等待畫面的頁面。等待畫面定時的向伺服器提交請求,以確定伺服器操作是否完成。另外正在執行的Action需要有一個攔截對象,攔截等待頁面的每一次請求,告訴等待頁面是否處理完成。

首先我們需要定義,等待頁面和Action是否完成的攔截對象
<action name="longLivedAction" class="com.jpleasure.LongLivedAction">
            <interceptor-ref name="completeStack"/>
            <interceptor-ref name="execAndWait"/>
            <result name="wait">/jsp/wait.jsp</result>
            <result name="success">/jsp/after.jsp</result>
</action>
<result name="wait">/jsp/wait.jsp</result>定義了等待畫面是/jsp/wait.jsp,當我們向伺服器提交請求之後,畫面會遷移到這個畫面。
<interceptor-ref name="execAndWait"/>定義了一個攔截對象,告訴等待畫面是否完成了長時間操作。
那麼等待畫面如何週期性查詢呢?
之需要一個指向該Action調用的一個不斷地重新整理即可。代碼如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>

<html>
<head>
    <title>Please wait</title>
    <meta http-equiv="refresh" content="5;url=<s:url includeParams='all'/> "/>
</head>
<body>
</body>
</html>

Please wait while we process your request.
<a href="<s:url includeParams="all" />"> Click Here</a> if this page does not reload automatically.

上述黑體部分表示,一旦畫面建立,就建立了一個重新整理,每5秒鐘重新整理一次,重新整理的廉潔為
url=<s:url includeParams=”all”/>,meta是標準瀏覽器支援的內容之一。
在啟動並執行時候可以看到產生需下的內容:
<meta http-equiv="refresh"
content="5;url=/wait/jsp/longLivedAction.action?name=zhangsf&amp;value=119 "/>
如果瀏覽器不支援自動重新整理也不要緊,可以讓客戶自己點擊Click Here來確定操作是否完成。

其實這裡最重要的是execAndWait Interceptor,每次向它攔截的Action發送請求的時候,execAndWait會確定Action操作是否完成,如果完成,將畫面定位到對應的頁面(通常是SUCCESS指向的頁面),否則紙箱wait指向的頁面。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.