本文討論Java Servlet和Java Server Page這兩種技術,它們可以用于隔離用戶界面與業務邏輯,實現多層次的Web應用程序。我們用一個簡單的應用來演示如何實現這種隔離,以及如何實現快速的部署和改變Web應用程序。 說明 本文說明如何隔離表現層與業務邏輯,實現多層次的Web應用程序 正文 適用操作系統: 跨平臺
隔離表現層與業務邏輯,實現多層次的Web應用程序
引言 在建立服務器端Web應用程序時,將表現層與業務邏輯分離可以更容易的創建動態的Web頁面,同時也可以讓沒有應用開發經驗的Web頁面設計人員能非常容易的改變Web站點的外觀。對于一個內容需要頻繁更新的Web站點,這就意味著更新周期更短,可以以最快的速度帶給本站點的訪問者以最新的內容。
早期的Web應用程序結構都很簡單,通常用戶界面與業務邏輯都混合在一起。修改這種應用的任何一方,都將使維護整個應用程序變得十分困難。將用戶界面與業務邏輯隔離就簡化了應用程序的維護,從而可以更快更容易的改變應用程序。本文討論Java Servlet和Java Server Page這兩種技術,它們可以用于隔離用戶界面與業務邏輯。我們用一個簡單的應用來演示如何實現這種隔離,以及如何實現快速的部署和改變應用程序。 首先,我們簡介一下Java Servlet和JSP及它們如何在一個Web應用中協調工作。
什么是Servlet? Servlet是平臺獨立的Java服務器端組件。它以多種方式來擴展服務器端的功能,同時將維護和支持的開銷也降到最小。Servlet不同于CGI腳本,它被編譯成Java的字節碼(bytecode),所以它沒有引入任何與平臺有關的因素,從而實現了真正的“Write Once,Run Anywhere”。
什么是Java Server Page(JSP)? JSP是建立含有動態內容的Web應用程序的Java技術。一個JSP頁面是一個文本文檔,包含了靜態的HTML內容和動態的動作標記。這些動作描述了如何處理返回給客戶的響應。在應用開發階段,JSP與Servlet差異很大,然而在運行時,它被編譯成Servlet,在JSP引擎中執行。JSP引擎存在于任何一種Web應用服務器中,如WebSphere V3.x。
Servlet和JSP協同工作 從理論上講,用戶可以只使用Servlet來接收從Web瀏覽器發來的HTTP請求,Servlet動態的處理請求(可能是查詢后端系統來完成請求),然后在Servlet中直接發送HTML或XML文檔的響應給瀏覽器。 上述方法在原理上是可行的,但它把Web頁面的產生也交由Java Servlet來做。如果Web頁面的設計人員要改變頁面的外觀就必須編輯、重新編譯Servlet。這將要求動態Web頁面的設計人員需要有應用程序開發經驗。顯然,我們需要將Web頁面的顯示與Servlet處理請求相隔離。 滿足上述需求的方法是采納Model-View-Controller(MVC)模型來建立Web應用程序。在MVC模型中,后端系統是我們的Model,用來創建用戶響應界面的模板是View,而把這兩者聯系起來的紐帶是Controller。JSP完美的對應于MVC模式中的View,Servlet包含了管理如何處理請求的邏輯,實際上就成為了Controller,而系統已有的業務規則就是Model。 我們來看一個例子,它使用了MVC模式實現表現層和業務邏輯的隔離,該例實現了從瀏覽器訪問3270后端系統的一個應用。
示例程序的體系結構如圖1所示。瀏覽器使用HTML和JSP實現了View,一組在應用服務器中的Java Servlet提供了Controller,后端的CICS等應用提供了業務規則或稱作Model。Servlet、HTML、JSP頁面調用的流程如圖2所示,并附有詳細的文字敘述。
示例應用流程詳解 發起請求
用戶用瀏覽器載入初始HTML頁面,該頁面是由Web使能的應用服務器提供的。應用服務器以與Web Server相同的方式來進行Web文件服務。這個頁面是整個Web應用的入口點。它使用了HTML FORM action標記來訪問Servlet。在我們的例子中,這個Servlet是LoginServlet。同樣附加的參數也隨著FORM的動作發給Servlet。 下面是一段例子: <FORM action="http://localhost:8080/servlet/LoginServlet" method="POST"> <input type="text" size="30" name="firstname"> <input type="text" size="30" name="surname"> . . <input type=hidden name=host value="localhost"> <input type=hidden name=port value="9876"> <input type=submit value=" Submit "> </FORM> 請求一般是以HTTP或HTTPS來發起,然后由Servlet來處理。它使用HttpServletRequest.getParameter()方法來訪問FORM表單提供的參數。 Servlet然后測試用戶是否有Session。Session用來將從遠程客戶端來的一系列請求關聯起來,這對于無狀態保持功能的HTTP協議是必須的。 Session可用如下方法來創建: HttpSession session = req.getSession(true) ; 對象可以被加入到Session中去: session.putValue(“host”,hostToConnectTo); session.putValue(“port”,tmpPort);
Controller Servlet負責調用處理用戶請求的JavaBean。它也負責創建對用戶的響應。在我們建議的應用結構中,響應將被傳遞到JSP。因此,Servlet被叫做Controller。 回到我們的例子。下面的代碼實例化一個類型CICSEmulator的新類叫newEmulator。這是一個由第三方廠商提供的3270終端仿真類,它提供了一組對仿真終端直接操縱的方法(類似的類也可以用IBM VisualAge for Java企業版中的Enterprise Access Builder來生成)。newEmulator可以從Session中傳遞變量,此例中變量為遠程主機和端口。
CICSEmulator newEmulator = new CICSEmulator(); newEmulator.setTN3270Port(portToConnectTo); newEmulator.setTN3270Host(hostToConnectTo);
第二個實例化的類是一個Java Bean叫做AcctDetails。它是一個數據訪問Bean,它將向后端的系統查找和獲取數據。AcctDetails將newEmulator來作為它的 3270終端,然后傳遞變量(姓和名)給它的set方法。
AcctDetails getAccountDetails = new AcctDetails(); getAccountDetails.set3270Emulator(newEmulator); getAccountDetails.setSurname(inputsurname); getAccountDetails.setFirstName(inputfirstname);
數據訪問Bean執行請求
Bean實例getAccountDetails的方法performWork(),它連接后端3270系統,并基于用戶提供的姓名來獲取用戶帳戶的細節。
try { getAccountDetails.performWork(); session.putValue("resultsBean", getAccountDetails); } catch ( IllegalStateException e ) { // handle the error }
如果執行成功,Servlet把getAccountDetails Bean放入用戶的session中。這個Bean的標識符為resultsBean,它包含了用戶查詢的結果,這些結果可以用Bean的get方法來訪問。
控制權傳給JSP
我們已經提到,MVC模式的重點就在于它隔離了表現層與業務邏輯。Servlet負責處理請求,它會去調用數據訪問Bean,數據訪問Bean getAccountDetails包含了從后端系統訪問和獲取數據的服務器端邏輯。后端系統(Model)包含了業務規則。而對用戶的響應(View)是由JSP創建出來的。 Servlet將request和response對象傳遞給JSP時遵循如下的語法: getServletContext().getRequestDispatcher(“/jspDemo/login.jsp”).forward(req,res); Forward方法允許Servlet將響應的處理傳給第三方。它的參數request和response必須就是調用servlet的service方法時傳遞的對象。 它使用 getRequestDispatcher對象來得到requestDispatcher,從而確定了到目的JSP的路徑。以“/”開始的JSP路徑名被解釋成相對于當前應用上下文環境的根路徑。
訪問ResultsBean
JSP負責創建對用戶的響應,它可以訪問getAccountDetails Bean的數據(使用標識符resultsBean來引用)。這些在HTML中用如下語法來完成:
<HTML> <BODY> . . <jsp:useBean id="resultsBean" scope="session" class="acct.AcctDetails " /> <jsp:getProperty name="resultsBean" property="*"/>
其中<JSP:useBean>是去查找已存在的對象(本例中是resultsBean)。本例中我們把getAccountDetails bean放入session中并命名為resultsBean。于是上述JSP語句就從session中得到了resultsBean,然后就可以通過訪問resultsBean的get方法來得到它的數據。 也可以通過如下JSP語句來實現:
<%= resultsBean.getDetails_Title() %> <%= resultsBean.getDetails_Initial() %>
上述語句也是JSP表達式的一個例子。在<%=和%>之間所有的內容被放入JSP引擎中處理,結果被作為輸出送給JSP文件。上述的兩個表達式將執行resultsBean的get方法來顯示用戶的title和Middle_Initial。同任何一種腳本語言(如JavaScript)一樣,JSP代碼可以在HTML頁面中任意嵌入。JSP的語法也非常簡單,這意味著JSP可以由Web頁面設計人員來維護而不是應用開發人員。開發人員負責的是servlet和數據訪問Bean。在JSP中的任何改變不會影響到servlet,反之亦然。
響應
JSP在請求時被動態翻譯成Java Servlet,并在應用服務器中緩存。后續JSP請求的響應將明顯加速。用戶收到的最終響應都是HTML頁面(以.jsp為擴展名),這些頁面包含了動態產生的內容。
總結:
在本文示例的應用結構中,客戶端瀏覽器發起的請求直接到了servlet,然后用數據訪問Bean來處理請求,從后端系統獲取數據。Servlet將結果包裝進resultsBean,把它放入session中,然后調用JSP來處理這個響應。Servlet是初始請求到產生響應的總體控制者。 JSP決定產生給用戶響應的內容。JSP只應當包含如何格式化表現層的邏輯。這種隔離的優點在于它創建了在應用中可重用的、可移植的、平臺獨立的組件,這些組件可以作為將來更大的應用的一部分。 隔離Servlet開發與JSP顯示為應用開發人員和Web頁面設計人員彼此獨立的工作帶來了極大的方便。同樣,這種方法也完美的符合了本文所介紹的MVC設計模型。
|