雙擊制御
有些時候一些操作會非常的耗費(fèi)時間(Long Lived Operation),例如這個數(shù)據(jù)庫的導(dǎo)出,表表生成等。有些時候程序的使用者看到很長時間服務(wù)器沒有反應(yīng),傾向于多次點(diǎn)擊提交按鈕。這樣恰恰相反,由于重新使服務(wù)器運(yùn)行相同的長時間操作,反而讓反應(yīng)時間更慢。
 
我們?nèi)绾蝸碇朴@樣的操作呢?
我們能不能在每個頁面生成的時候,自動生成一個特殊的隱藏字段,這個隱藏字段具有唯一性。每次向服務(wù)器提交請求的時候,服務(wù)器就記錄下這個隱藏字段,當(dāng)在看到有相同的特殊字段的內(nèi)容提交時,服務(wù)器認(rèn)為這是重復(fù)提交,將畫面定位到一個特殊的畫面來提示客戶重復(fù)提交了數(shù)據(jù)。
 
在Struts2中,內(nèi)容了對雙擊的制御操作,特殊的隱藏字段叫做token。
 
如何在生成頁面的時候生成token字段?
使用token標(biāo)簽。
代碼如下:
<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 />標(biāo)簽用來生成一個唯一的隱藏字段,在運(yùn)行的時候生成的內(nèi)容如下:
<input type="hidden" name="struts.token" value="C21ZWHEH0Q4B6FY15ZO5BFM1I9W8SIQH" />
 
如何在服務(wù)器上記錄已經(jīng)提交的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"/>表 示所有的請求必須經(jīng)過token Interceptor,token Interceptor作用就是紀(jì)錄所有已經(jīng)提交的token。那么發(fā)現(xiàn)提交的token被重復(fù)提交的時候怎么辦呢?也許大家已經(jīng)猜到了,他會重定向到 invalid.token所指向的頁面,也就是/jsp/invalidToken.jsp。
 
基于Interceptor的執(zhí)行順序按照struts.xml中定義的順序,為了更早的結(jié)束重復(fù)提交的處理,應(yīng)該將Token Interceptor放在所有Interceptor的最面。
 
有了上述的Token Interceptor,可以防止客戶重復(fù)提交,大大地降低了服務(wù)器的負(fù)荷。但是對用戶來說,可能會很不方便,一不小心點(diǎn)擊了提交按鈕,進(jìn)入到了invalid.token頁面,就再也回不去了,上述的操作就再也看不見了。
 
等待畫面
我們能不能提供一個等待畫面呢?
每次我們提交之后畫面立即遷移到一個類似狀態(tài)條的畫面,這個畫面不斷的向服務(wù)器請求,以確定Action是否執(zhí)行完畢,一旦Action執(zhí)行完畢,立即定位到正確的畫面。這樣不是更好。
 
Struts2也提供了對等待畫面的支持。
首先當(dāng)我們提交完成的時候,畫面會前一到一個叫做等待畫面的頁面。等待畫面定時的向服務(wù)器提交請求,以確定服務(wù)器操作是否完成。另外正在執(zhí)行的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,當(dāng)我們向服務(wù)器提交請求之后,畫面會遷移到這個畫面。
<interceptor-ref name="execAndWait"/>定義了一個攔截對象,告訴等待畫面是否完成了長時間操作。
那么等待畫面如何定期的查詢呢?
之需要一個指向該Action調(diào)用的一個不斷地刷新即可。代碼如下:
<%@ 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是標(biāo)準(zhǔn)瀏覽器支持的內(nèi)容之一。
在運(yùn)行的時候可以看到生成需下的內(nèi)容:
<meta http-equiv="refresh"
content="5;url=/wait/jsp/longLivedAction.action?name=zhangsf&amp;value=119 "/>
如果瀏覽器不支持自動刷新也不要緊,可以讓客戶自己點(diǎn)擊Click Here來確定操作是否完成。
 
其實(shí)這里最重要的是execAndWait Interceptor,每次向它攔截的Action發(fā)送請求的時候,execAndWait會確定Action操作是否完成,如果完成,將畫面定位到對應(yīng)的頁面(通常是SUCCESS指向的頁面),否則紙箱wait指向的頁面。


ExtJS教程- Hibernate教程-Struts2 教程-Lucene教程