六月婷婷综合激情-六月婷婷综合-六月婷婷在线观看-六月婷婷在线-亚洲黄色在线网站-亚洲黄色在线观看网站

明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

JSP編程進度條設計案例

[摘要]許多Web應用、企業應用涉及到長時間的操作,例如復雜的數據庫查詢或繁重的XML處理等,雖然這些任務主要由數據庫系統或中間件完成,但任務執行的結果仍舊要借助JSP才能發送給用戶。本文介紹了一種通過改進前端表現層來改善用戶感覺、減輕服務器負載的辦法。當JSP調用一個必須長時間運行的操作,且該操作的結果...

許多Web應用、企業應用涉及到長時間的操作,例如復雜的數據庫查詢或繁重的XML處理等,雖然這些任務主要由數據庫系統或中間件完成,但任務執行的結果仍舊要借助JSP才能發送給用戶。本文介紹了一種通過改進前端表現層來改善用戶感覺、減輕服務器負載的辦法。當JSP調用一個必須長時間運行的操作,且該操作的結果不能(在服務器端)緩沖,用戶每次請求該頁面時都必須長時間等待。很多時候,用戶會失去耐心,接著嘗試點擊瀏覽器的刷新按鈕,最終失望地離開。 本文介紹的技術是把繁重的計算任務分離開來,由一個獨立的線程運行,從而解決上述問題。當用戶調用JSP頁面時,JSP頁面會立即返回,并提示用戶任務已經啟動且正在執行;JSP頁面自動刷新自己,報告在獨立線程中運行的繁重計算任務的當前進度,直至任務完成。
一、模擬任務
 首先我們設計一個TaskBean類,它實現java.lang.Runnable接口,其run()方法在一個由JSP頁面(start.jsp)啟動的獨立線程中運行。終止run()方法執行由另一個JSP頁面stop.jsp負責。TaskBean類還實現了java.io.Serializable接口,這樣JSP頁面就可以將它作為JavaBean調用:
 package test.barBean;
import java.io.Serializable;
 public class TaskBean implements Runnable, Serializable {
    private int counter;
    private int sum;
    private boolean started;
    private boolean running;
    private int sleep;
     public TaskBean() {
        counter = 0;
        sum     = 0;
        started = false;
        running = false;
        sleep   = 100;
    }
}
 TaskBean包含的“繁重任務”是計算1+2+3…+100的值,不過它不通過100*(100+1)/2=5050公式計算,而是由run()方法調用work()方法100次完成計算。work()方法的代碼如下所示,其中調用Thread.sleep()是為了確保任務總耗時約10秒。
 protected void work() {
    try {
        Thread.sleep(sleep);
        counter++;
        sum += counter;
    } catch (InterruptedException e) {
        setRunning(false);
    }
}
 
status.jsp頁面通過調用下面的getPercent()方法獲得任務的完成狀況:
 public synchronized int getPercent() {
    return counter;
}如果任務已經啟動,isStarted()方法將返回true:
public synchronized boolean isStarted() {
    return started;
}
 
 如果任務已經完成,isCompleted()方法將返回true:
 public synchronized boolean isCompleted() {
    return counter == 100;
}
 
 如果任務正在運行,isRunning()方法將返回true:
 public synchronized boolean isRunning() {
    return running;
}
 
SetRunning()方法由start.jsp或stop.jsp調用,當running參數是true時。SetRunning()方法還要將任務標記為“已經啟動”。調用setRunning(false)表示要求run()方法停止執行。
 public synchronized void setRunning(boolean running) {
    this.running = running;
    if (running)
        started  = true;
}
 
任務執行完畢后,調用getResult()方法返回計算結果;如果任務尚未執行完畢,它返回null:
 public synchronized Object getResult() {
    if (isCompleted())
        return new Integer(sum);
    else
        return null;
}
 
當running標記為true、completed標記為false時,run()方法調用work()。在實際應用中,run()方法也許要執行復雜的SQL查詢、解析大型XML文檔,或者調用消耗大量CPU時間的EJB方法。注意“繁重的任務”可能要在遠程服務器上執行。報告結果的JSP頁面有兩種選擇:或者等待任務結束,或者使用一個進度條。
 public void run() {
    try {
        setRunning(true);
        while (isRunning() && !isCompleted())
            work();
    } finally {
        setRunning(false);
    }
}二、啟動任務

 start.jsp是web.xml部署描述符中聲明的歡迎頁面,web.xml的內容是:
 <?xml version="1.0" encoding="GB2312"?>
 <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
 <web-app>
    <welcome-file-list>
        <welcome-file>start.jsp</welcome-file>
    </welcome-file-list>
</web-app>
 start.jsp啟動一個專用的線程來運行“繁重的任務”,然后把HTTP請求傳遞給status.jsp。
 start.jsp頁面利用<jsp:useBean>標記創建一個TaskBean的實例,將scope屬性定義為session使得對于來自同一瀏覽器的HTTP請求,其他頁面也能提取到同一個Bean對象。start.jsp通過調用session.removeAttribute("task")確保<jsp:useBean>創建了一個新的Bean對象,而不是提取一個舊對象(例如,同一個用戶會話中更早的JSP頁面所創建的Bean對象)。
 下面是start.jsp頁面的代碼清單:
 <% session.removeAttribute("task"); %>
 <jsp:useBean id="task" scope="session"
    class="test.barBean.TaskBean"/>
 <% task.setRunning(true); %>
<% new Thread(task).start(); %>
<jsp:forward page="status.jsp"/>
 
start.jsp創建并設置好TaskBean對象之后,接著創建一個Thread,并將Bean對象作為一個Runnable實例傳入。調用start()方法時新創建的線程將執行TaskBean對象的run()方法。
 現在有兩個線程在并發執行:執行JSP頁面的線程(稱之為“JSP線程”),由JSP頁面創建的線程(稱之為“任務線程”)。接下來,start.jsp利用調用status.jsp,status.jsp顯示出進度條以及任務的執行情況。注意status.jsp和start.jsp在同一個JSP線程中運行。
 start.jsp在創建線程之前就把TaskBean的running標記設置成了true,這樣,即使當JSP線程已開始執行status.jsp而任務線程的run()方法尚未啟動,也能夠確保用戶會得到“任務已開始運行”的狀態報告。
 將running標記設置成true、啟動任務線程這兩行代碼可以移入TaskBean構成一個新的方法,然后由JSP頁面調用這個新方法。一般而言,JSP頁面應當盡量少用Java代碼,即我們應當盡可能地把Java代碼放入Java類。不過本例中我們不遵從這一規則,把new Thread(task).start()直接放入start.jsp突出表明JSP線程創建并啟動了任務線程。
 在JSP頁面中操作多線程必須謹慎,注意JSP線程和其它線程實際上是并發執行的,就象在桌面應用程序中,我們用一個線程來處理GUI事件,另外再用一個或多個線程來處理后臺任務。不過在JSP環境中,考慮到多個用戶同時請求某一個頁面的情況,同一個JSP頁面可能會在多個線程中同時運行;另外,有時同一個用戶可能會向同一個頁面發出多個請求,雖然這些請求來自同一個用戶,它們也會導致服務器同時運行一個JSP頁面的多個線程。三、任務進度
status.jsp頁面利用一個HTML進度條向用戶顯示任務的執行情況。首先,status.jsp利用<jsp:useBean>標記獲得start.jsp頁面創建的Bean對象:
 <jsp:useBean id="task" scope="session"
    class="test.barBean.TaskBean"/>
 為了及時反映任務執行進度,status.jsp會自動刷新。JavaScript代碼setTimeout("location='status.jsp'", 1000)將每隔1000毫秒刷新頁面,重新請求status.jsp,不需要用戶干預。
 <HTML>
 <HEAD>
    <TITLE>JSP進度條</TITLE>
    <% if (task.isRunning()) { %>
        <SCRIPT LANGUAGE="JavaScript">
            setTimeout("location='status.jsp'", 1000);
        </SCRIPT>
    <% } %>
</HEAD>
 <BODY>
 進度條實際上是一個HTML表格,包含10個單元——即每個單元代表任務總體的10%進度。
 <H1 ALIGN="CENTER">JSP進度條</H1>
     <H2 ALIGN="CENTER">
        結果: <%= task.getResult() %><BR>
        <% int percent = task.getPercent(); %>
        <%= percent %>%
    </H2>
     <TABLE WIDTH="60%" ALIGN="CENTER"
            BORDER=1 CELLPADDING=0 CELLSPACING=2>
        <TR>
            <% for (int i = 10; i <= percent; i += 10) { %>
                <TD WIDTH="10%" BGCOLOR="#000080">&nbsp;</TD>
            <% } %>
            <% for (int i = 100; i > percent; i -= 10) { %>
                <TD WIDTH="10%">&nbsp;</TD>
            <% } %>
        </TR>
    </TABLE>
 
任務執行情況分下面幾種狀態:正在執行,已完成,尚未開始,已停止:
 <TABLE WIDTH="100%" BORDER=0 CELLPADDING=0 CELLSPACING=0>
        <TR>
            <TD ALIGN="CENTER">
                <% if (task.isRunning()) { %>
                    正在執行
                <% } else { %>
                    <% if (task.isCompleted()) { %>
                        完成
                    <% } else if (!task.isStarted()) { %>
                        尚未開始
                    <% } else { %>
                        已停止
                    <% } %>
                <% } %>
            </TD>
        </TR>頁面底部提供了一個按鈕,用戶可以用它來停止或重新啟動任務:
 <TR>
            <TD ALIGN="CENTER">
                <BR>
                <% if (task.isRunning()) { %>
                    <FORM METHOD="GET" ACTION="stop.jsp">
                        <INPUT TYPE="SUBMIT" VALUE="停止">
                    </FORM>
                <% } else { %>
                    <FORM METHOD="GET" ACTION="start.jsp">
                        <INPUT TYPE="SUBMIT" VALUE="開始">
                    </FORM>
                <% } %>
            </TD>
        </TR>
    </TABLE>
</BODY></HTML>
 只要不停止任務,約10秒后瀏覽器將顯示出計算結果5050:
 四、停止任務
 stop.jsp頁面把running標記設置成false,從而停止當前的計算任務:
 <jsp:useBean id="task" scope="session"
    class="test.barBean.TaskBean"/>
 <% task.setRunning(false); %>
<jsp:forward page="status.jsp"/>
 
注意最早的Java版本提供了Thread.stop方法,但JDK從1.2版開始已經不贊成使用Thread.stop方法,所以我們不能直接調用Thread.stop()。
 第一次運行本文程序的時候,你會看到任務的啟動有點延遲;同樣地,第一次點擊“停止”按鈕時也可以看到任務并沒有立即停止運行(特別是如果機器配置較低的話,延遲的感覺更加明顯),這些延遲都是由于編譯JSP頁面導致的。編譯好JSP頁面之后,應答速度就要快多了。
 五、實際應用
 進度條不僅使得用戶界面更加友好,而且對服務器的性能也有好處,因為進度條會不斷地告訴用戶當前的執行進度,用戶不會再頻繁地停止并重新啟動(刷新)當前的任務。另一方面,創建單獨的線程來執行后臺任務也會消耗不少資源,必要時可考慮通過一個線程池來實現Thread對象的重用。另外,頻繁地刷新進度頁面也增加了網絡通信開銷,所以務必保持進度頁面簡潔短小。
 在實際應用中,后臺執行的繁重任務可能不允許停止,或者它不能提供詳細的執行進度數據。例如,查找或更新關系數據庫時,SQL命令執行期間不允許中途停止——不過如果用戶表示他想要停止或中止任務,程序可以在SQL命令執行完畢后回退事務。
 解析XML文檔的時候,我們沒有辦法獲知已解析內容精確的百分比。如果用DOM解析XML文檔,直到解析完成后才得到整個文檔樹;如果用SAX,雖然可以知道當前解析的內容,但通常不能確定還有多少內容需要解析。在這些場合,任務的執行進度只能靠估計得到。
 估計一個任務需要多少執行時間通常是很困難的,因為它涉及到許多因素,即使用實際測試的辦法也無法得到可靠的結論,因為服務器的負載隨時都在變化之中。一種簡單的辦法是測量任務每次執行所需時間,然后根據最后幾次執行的平均時間估算。如果要提高估計時間的精確度,應當考慮實現一種針對應用特點的算法,綜合考慮多種因素,例如要執行的SQL語句類型、要解析的XML模式的復雜程度,等等。
 結束語:本文例子顯示出用JSP、Java、HTML和JavaScript構造進度條是相當容易的,真正困難的是如何將它用到實際應用之中,特別是獲得后臺任務的進度信息,但這個問題沒有通用的答案,每一種后臺執行的任務都有它自己的特點,必須按照具體情況具體分析。 (出處:PConline)


主站蜘蛛池模板: 日本国产视频 | 色就干| 日本一区二区三区欧美在线观看 | 色我网站| 日韩黄色一级 | 日韩一区二区久久久久久 | 色噜噜狠狠网站 | 天堂色在线 | 小泽玛利亚久久一区二区三区 | 午夜小影院 | 我想看一级毛片免费的 | 午夜视频在线观看完整版 | 直接黄91麻豆网站 | 伊人国产在线视频 | 婷婷激情五月 | 亚洲a级毛片 | 欧美天天视频 | 日韩精品亚洲专区在线观看 | 日本三级香港三级人妇99 | 天天干夜夜看 | 星辰影院在线观看高清免费观看 | 欧美在线a级高清 | 视频午夜 | 亚洲色大成网站www 亚洲三级中文字幕 | 日韩中文字幕高清在线专区 | 色久视频 | 日韩精品一区二区三区中文在线 | 色天天综合色天天碰 | 色狠狠成人综合网 | 在线 色| 一二三四五影视在线播放 | 深夜视频免费看 | 午夜网站在线观看免费网址免费 | 欧美亚洲激情 | 天堂中文在线www | 武则天一级淫片免费放 | 一级片一级毛片 | 午夜国产精品不卡在线观看 | 日日噜噜噜夜夜爽爽狠狠69 | 日本在线免费看片 | 深夜福利网站在线 |