對於一些須要較長時間才能完成的任務,在Web開發中,會由HTTP協議會由於超時而斷開而面臨許多風險,這是在桌面開發未曾遇到的。Struts 2提供的execAndWait攔截器就是爲了處理和應付這種狀況而設計的。注意,該攔截器不在"defaultStack"中,因此必須在使用它的動做裏聲明它,而且必須放在攔截器棧的最後一個。
使用了該攔截器後,動做依然正常執行,只是該攔截器會分配一個後臺線程處理動做的運行,並在動做完成以前把用戶帶到一個"等待"頁面。,該頁面每隔一段時間刷新一次,直到那個後臺線程執行完畢爲止。若是用戶隨後又觸發了同一個動做,但頂一個動做還沒有執行完畢,這個攔截器將繼續向用戶發送"等待"結果;若是他已經執行完畢,用戶會看到該動做的最終結果。
"等待"結果的行爲與"dispatcher"結果的行爲很類似,可是要注意的是,"等待"結果對應的視圖帶有以下的meta標籤:
<meta http-equiv="refresh" content="5;url=/Struts2/default_progressbar.action"/>
該標籤的做用就每隔多少秒就從新加載一次一樣的URL。這裏"5"表示5秒,"url=/Struts2/default_progressbar.action"表示要加載的URL。
Struts 2是一個靈活強大的框架,若是你不喜歡Struts 2提供的默認"等待頁面",你也能夠本身設計本身的等待頁面,若在動做聲明中,沒有找到"等待"結果,將使用默認值。 javascript
execAndWait攔截器
execAndWait攔截器 能夠接收如下參數:
- threadPriority:分配給相關線程的優先級,默認值爲Thread.NORM_PRIORITY。
- delay:向用戶發送"等待"結果前的毫秒數,默認值爲0。若是你不想馬上發送"等待"結果,能夠將該參數設置爲一個值。例如,你想讓動做超過2秒還未完成時才發送"等待"結果,須要將其值設置爲2000.
- delaySleepInterval:每隔多少毫秒喚醒主線程(處理動做的後臺線程)去檢查後臺線程是否已經處理完成,默認值是100。這個值設爲0時無效。
模擬長時間運行的Action
爲了示例,首先來模擬一個運行時間長的Action:在這個Action中首先定義了一個int類型的progress屬性及其getter/setter,用來向外界返回當前任務的完成進度。在execute方法中,讓Action所在的線程在每次循環的時候sleep一秒鐘,每次循環把進度加十。 css
這樣,隨着外界不斷訪問progress屬性,就能夠知道當前任務運行的進度了。示例代碼以下: html
java代碼:
- public class WaitAction extends ActionSupport{
- /**
- * 準備向等待頁面返回工做的進度
- */
- private int progress;
- public int getProgress() {
- return progress;
- }
- public void setProgress(int progress) {
- this.progress = progress;
- }
-
- public String execute() throws Exception {
- //循環十次,每次線程睡1秒,且進度加10
- for (int i=0;i<10;i++){
- Thread.sleep(1000L);
- progress += 10;
- }
- return SUCCESS;
- }
- }
19.2.2配置Action
首先,在配置Action的時候,要讓這個Action引用execAndWait攔截器,並且,這個攔截器會停止聲明在它之後的攔截器的執行,所以這個攔截器的引用要出如今defaultStack攔截器棧以後。 java
其次,還要爲這個Action聲明一個名稱爲wait的Result,由它來指定具體的等待頁面。示例代碼以下: 瀏覽器
java代碼:
- <package name="helloworld" extends="struts-default">
- <action name="waitAction" class="cn.javass.wait.WaitAction">
- <interceptor-ref name="defaultStack"/>
- <interceptor-ref name="execAndWait"/>
- <result>/wait/success.jsp</result>
- <result name="wait">/wait/wait.jsp</result>
- </action>
- </package>
19.2.3實現「進度條」頁面
因爲HTTP頁面在顯示以後,不會再與服務器交互,因此,要不斷的刷新這個「進度條」頁面才行。 服務器
能夠簡單的使用<html>標籤中的<meta>標籤來設置這個頁面不斷進行自我刷新。示例代碼以下: 框架
java代碼:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">
- <title>Insert title here</title>
- </head>
- <body>
- 您好,任務還未完成,已經運行到了任務的<s:property value="progress"/>%
- </body>
- </html>
<meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">這句話表明了當前頁面會在顯示2秒以後訪問」 /helloworld/waitAction.action」這個URL。因爲wait.jsp就是從這個Action中跳轉出來的,因此就至關於每隔2秒就刷新一次wait.jsp頁面。一樣能夠經過<s:property/>標籤訪問值棧。 jsp
19.2.4實現完成頁面
實現一個完成頁面,在完成頁面中,簡單的告知用戶已經成功執行。示例代碼以下: 測試
java代碼:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- </head>
- 恭喜您,任務結束!
19.2.5運行測試
在瀏覽器的地址欄輸入「http://localhost:9080/helloworld/waitAction.action」,來直接訪問waitAction。 ui
在訪問這個WaitAction的時候,第一次訪問會使execute方法開始運行。可是,因爲引用了execAndWait攔截器,並非一直等到execute方法運行完以後再跳轉到下一個頁面,而是立刻跳轉到struts.xml中註冊的名爲wait的Result,也就是wait.jsp。
在wait.jsp中仍然能夠訪問值棧裏面的值,所以,經過訪問了progress屬性來顯示當前任務運行的進度。以下圖所示:
圖19.1 顯示任務進度一
在wait.jsp,又指定了每隔2秒訪問一次WaitAction,這時候,只要execute方法還沒運行完,就立刻再次轉發到名爲wait的Result,依次類推,直到execute方法運行完以後。所以頁面顯示的進度數據會一直增長,如圖所示:
圖19.2 顯示任務進度二
所以,若是不引用execAndWait攔截器,在訪問WaitAction的時候,本應該等到10秒後瀏覽器纔有反應。可是,如今引用了execAndWait攔截器,在訪問WaitAction的時候,立刻跳轉到了wait.jsp,並且每隔2秒刷新一次,直到10秒以後,直到execute方法運行完成,瀏覽器正確的跳轉到success.jsp。以下圖所示:
圖19.3 任務結束
19.2.6圖形化的進度條
看到這裏,確定有朋友會說,這哪裏像是進度條啊,明明只是顯示了一個運行進度而已。確實,從表現上看,不像咱們熟悉的進度條,尤爲是不像圖形化的進度條。
1:JavaScript的圖形化進度條
其實,要實現圖形化的進度條也很簡單,使用Javascript就能夠很方便的實現。先看個最簡單的Javascript的進度條的實現,示例代碼以下:
java代碼:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <style type="text/css">
- #out{width:300px;height:20px;background:#EEE000;}
- #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}
- </style>
- </HEAD>
- <BODY onload="start();" >
- <div id='out'>
- <div id="in" style="width:10%">10%</div>
- <div>
- <script type="text/javascript">
- var i=0;
- function start(){
- ba=setInterval("begin()",100);
- }
- function begin(){
- i+=1;
- if(i<=100){
- document.getElementById("in").style.width=i+"%";
- document.getElementById("in").innerHTML=i+"%";
- }else{
- clearInterval(ba);
- document.getElementById("out").style.display="none";
- document.write("進度條運行成功");
- }
- }
- </script>
- </BODY>
具體的Javascript的知識,這裏就不去深刻了,要注意下面幾點:
- 進度條的效果是經過兩個Div來實現的,id爲out的div做爲底框,id爲in的div做爲動態顯示進度的進度框
- 啓動方法是<body>元素的onload屬性所指定的方法
- Start方法裏面的setInterval(表達式,間隔時間),意思是:啓動後,每隔指定的間隔時間,就執行前面的表達式一次,這個方法至關於一個定時器
- 在begin方法裏面,經過動態的改變id爲in的div框所包含的文字,從而實現動態顯示進度的效果
- 運行到最後,必定要記得清除掉setInterval所設置的定時器,用的是clearInterval方法
固然,使用Javascript來實現進度條有不少種方式,這裏只是其中的一種而已。
2:把Struts2的進度條圖形化
接下來把前面的wait.jsp頁面顯示的進度,改爲圖形化的進度條的形式。
一樣須要使用Javascript來圖形化的顯示進度條,只不過具體的進度數據應該從Struts2的waitAction中去獲取,也就是直接把從Action中獲取的進度數據,直接賦值給Javascript,而後經過Javascript來顯示進度條。示例代碼以下:
java代碼:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <style type="text/css">
- #out{width:300px;height:20px;background:#EEE000;}
- #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}
- </style>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">
- <title>Insert title here</title>
- </head>
- <body>
- <BODY onload="start();" >
- <div id='out'>
- 您好,任務還未完成,已經運行到了任務的<div id="in" style="width:10%">10%</div>
- <div>
- <script type="text/javascript">
- function start(){
- ba=setInterval("begin()",100);
- }
- function begin(){
- var i = <s:property value="progress"/>;
- if(i<=100){
- document.getElementById("in").style.width=i+"%";
- document.getElementById("in").innerHTML=i+"%";
- }else{
- clearInterval(ba);
- document.getElementById("out").style.display="none";
- document.write("進度條運行成功");
- }
- }
- </script>
- </BODY>
- </html>
最重要的變化就在加粗的那句話,把從Action獲取的數據直接設置給了Javascript,要注意這個過程是在服務端完成的,到了客戶端,值已經設置好了,所以Javascript一樣能正常地運行。
運行URL:http://localhost:9080/helloworld/waitAction.action,測試一下看看效果,以下圖所示:
圖19.4 Struts2的進度條圖形化
進度條會不斷滾動,直到運行結束,轉向success.jsp爲止。
本文參考自:http://www.cnblogs.com/suxiaolei/archive/2011/11/06/2232009.html
http://sishuok.com/forum/blogPost/list/4174.html