爲Struts2 應用程序建立進度條(等待頁面)

     

     對於一些須要較長時間才能完成的任務,在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代碼:
  1. public class WaitAction extends ActionSupport{  
  2.     /** 
  3.      * 準備向等待頁面返回工做的進度 
  4.      */  
  5.     private int progress;  
  6.     public int getProgress() {  
  7.         return progress;  
  8.     }  
  9.     public void setProgress(int progress) {  
  10.         this.progress = progress;  
  11.     }  
  12.       
  13.     public String execute() throws Exception {  
  14.         //循環十次,每次線程睡1秒,且進度加10  
  15.         for (int i=0;i<10;i++){  
  16.             Thread.sleep(1000L);  
  17.             progress += 10;  
  18.         }  
  19.         return SUCCESS;  
  20.     }  
  21. }  

19.2.2配置Action

       首先,在配置Action的時候,要讓這個Action引用execAndWait攔截器,並且,這個攔截器會停止聲明在它之後的攔截器的執行,所以這個攔截器的引用要出如今defaultStack攔截器棧以後。 java

       其次,還要爲這個Action聲明一個名稱爲wait的Result,由它來指定具體的等待頁面。示例代碼以下: 瀏覽器

 

java代碼:
  1. <package name="helloworld" extends="struts-default">  
  2.     <action name="waitAction" class="cn.javass.wait.WaitAction">  
  3.         <interceptor-ref name="defaultStack"/>  
  4.         <interceptor-ref name="execAndWait"/>  
  5.         <result>/wait/success.jsp</result>  
  6.         <result name="wait">/wait/wait.jsp</result>  
  7.     </action>  
  8. </package>  

19.2.3實現「進度條」頁面

       因爲HTTP頁面在顯示以後,不會再與服務器交互,因此,要不斷的刷新這個「進度條」頁面才行。 服務器

能夠簡單的使用<html>標籤中的<meta>標籤來設置這個頁面不斷進行自我刷新。示例代碼以下: 框架

 

java代碼:
  1. <%@ page language="java" contentType="text/html; charset=gb2312"  
  2.     pageEncoding="gb2312"%>  
  3. <%@taglib prefix="s" uri="/struts-tags" %>  
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  
  5.  "http://www.w3.org/TR/html4/loose.dtd">  
  6. <html>  
  7. <head>  
  8. <meta http-equiv="Content-Type" content="text/html; charset=gb2312">  
  9. <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">  
  10. <title>Insert title here</title>  
  11. </head>  
  12. <body>  
  13.     您好,任務還未完成,已經運行到了任務的<s:property value="progress"/>%  
  14. </body>  
  15. </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代碼:
  1. <%@ page language="java" contentType="text/html; charset=gb2312"  
  2.     pageEncoding="gb2312"%>  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=gb2312">  
  5. </head>  
  6.     恭喜您,任務結束!  

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代碼:
  1. <%@ page language="java" contentType="text/html; charset=gb2312"  
  2.     pageEncoding="gb2312"%>  
  3. <style type="text/css">  
  4. #out{width:300px;height:20px;background:#EEE000;}  
  5. #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}  
  6. </style>  
  7. </HEAD>  
  8. <BODY onload="start();" >  
  9. <div id='out'>  
  10.     <div id="in" style="width:10%">10%</div>  
  11. <div>  
  12. <script type="text/javascript">  
  13.     var i=0;  
  14.     function start(){  
  15.         ba=setInterval("begin()",100);  
  16.     }  
  17.     function begin(){  
  18.         i+=1;  
  19.         if(i<=100){  
  20.             document.getElementById("in").style.width=i+"%";  
  21.             document.getElementById("in").innerHTML=i+"%";  
  22.         }else{  
  23.             clearInterval(ba);  
  24.             document.getElementById("out").style.display="none";  
  25.             document.write("進度條運行成功");  
  26.         }  
  27.     }  
  28. </script>  
  29. </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代碼:
  1. <%@ page language="java" contentType="text/html; charset=gb2312"  
  2.     pageEncoding="gb2312"%>  
  3. <%@taglib prefix="s" uri="/struts-tags" %>  
  4. <html>  
  5. <head>  
  6. <style type="text/css">  
  7. #out{width:300px;height:20px;background:#EEE000;}  
  8. #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}  
  9. </style>  
  10. <meta http-equiv="Content-Type" content="text/html; charset=gb2312">  
  11. <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">  
  12. <title>Insert title here</title>  
  13. </head>  
  14. <body>  
  15. <BODY onload="start();" >  
  16. <div id='out'>  
  17.     您好,任務還未完成,已經運行到了任務的<div id="in" style="width:10%">10%</div>  
  18. <div>  
  19. <script type="text/javascript">     
  20.     function start(){  
  21.         ba=setInterval("begin()",100);  
  22.     }  
  23.     function begin(){  
  24.         var i = <s:property value="progress"/>;  
  25.         if(i<=100){  
  26.             document.getElementById("in").style.width=i+"%";  
  27.             document.getElementById("in").innerHTML=i+"%";  
  28.         }else{  
  29.             clearInterval(ba);  
  30.             document.getElementById("out").style.display="none";  
  31.             document.write("進度條運行成功");  
  32.         }  
  33.     }  
  34. </script>  
  35. </BODY>  
  36. </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

相關文章
相關標籤/搜索