用Struts開發基於MVC的Web應用
MVC介紹
MVC模式是一種非常理想化的設計模式,應用MVC模式完成兩個以上項目的人都有同樣的體會,他們已經對以前的工作方法進行了徹底的改造。工作模式的改變要付出痛苦的代價,但現在你有現成的技術架構可以采用,避免在項目中自己開發、摸索。它就是開源Apache Struts framework,它提供了實現MVC設計模式最好的實現工具。
在本文中,我們將簡單了解、體會一下模型-視圖-控製器(MVC)設計模式,特別地,我們來看看如何用Struts架構來完美地實現MVC模式。我們先從理論上簡單地描述MVC模式,然後用我們一個簡單的例子來實現我們自己的MVC架構。在對MVC模式有了了解後,我們用Struts來看這個新技術是如何幫助我們迅速、簡單地創建基於MVC的Web應用。
模型-視圖-控製器(Model-View-Controller)模式
MVC模式最早是在Smalltalk(一種麵向對象的語言)這種程序語言設計中被提出來的。我們暫時先忽略它的曆史,集中注意力在關注它怎樣被應用在Web應用開發中。
當Java的Servlets技術最開始出現的時候,程序員們立刻意識到這是一項極其有用的技術。與同時代的CGI Web開發技術相比,Servlets更快,更靈活,更可靠,更強大。然而,開發基於Servlets技術的Web應用有一個巨大的缺陷--需要使用例如out.println之類的語句來輸出瀏覽器識別的HTML。頻繁使用這個方法是個錯誤的傾向,開發極其浪費時間(程序員需要經常退出所有應用程序進行重新編譯)。並且這也使修改Web頁麵的工作也變得很困難,因為Web的表現和邏輯在一堆令人恐懼的代碼中摻乎在一起。
於是作為解決方法的JavaServer Pages(JSP)出現了,它們將Servlets變成它們運行的結果。應用JSP技術,我們將業務邏輯用一係列夾雜在HTML中的<%>標識來表達。以開發JSP為核心的應用盡管比以Servlet為核心的應用有進步,但看起來仍然是雜亂無章的,仍然需要用額外的代碼來控製應用頁麵的流轉。在充滿格式化代碼的JSP頁麵上,沒有地方來增加這樣額外的控製代碼。顯然需要尋找別的出路。
不久人們認識到同時應用JSP和Servlets兩種技術開發Web應用是一種不錯的選擇。畢竟,Servlets擅長處理業務邏輯的編程,處理請求,控製功能頁麵的流轉,而JSP則是格式化請求處理結果,通過瀏覽器獲得用戶輸入。這種工作機製後來變成了人們長說的Model2(用JSP或Servlets中單獨的一種實現web應用被稱做Model 1).
Model 2不是一項革命性的新模式,其實它是來自於Smalltalk語言研發過程中出現的MVC模式。大多數情況下,Java程序員趨向於可完全互換地使用這兩個名詞。
什麼是MVC模式?
此前我們已對MVC在開發基於Java技術Web應用中的使用曆史有了初步的了解,現在讓我們來看看這種模式的細節。本節中,我們來準確地了解一下Models、Views、Controllers的確切含義,它們實現的任務,以及如何利用它們實現一個簡單的MVC框架。我們先來看看Model、View、Controller是如何交互工作的。
圖SM01
Figure 1 : Model 2/MVC架構
如上圖所示,用戶通過提交requests與Controller組件(通常表現為Servlets)交互。接著Controller組件實例化Model組件(通常表現為JavaBeans或者類似技術),並且根據應用的邏輯操縱它們。一旦Model被創建,Controller決定下一個為用戶顯示的View(常常表現為JSP),同時View與Model交互操作,獲得並為用戶顯示相關數據。在它被提交到Controller重新開始此操作之前,View可以修改Model的狀態。
為了更全麵得理解組件之間的交互,我們來看一個應用這種框架實現的簡單例子。這是一個完成提交、記錄用戶登陸信息的簡單應用。
View
本例的View由兩個簡單的JSP頁麵組成。請參考代碼 (login.jsp、welcome.jsp)。
1>login.jsp隻是簡單地提供了用戶輸入姓名和口令的操作界麵。輸入完成後,登陸頁提交輸入到controller Servlet(代碼如後Controller部分說明),告訴它需要調用"登陸操作(login action)"(操作參數通過form來傳遞);
2>welcome.jsp頁麵利用用戶前頁提供的用戶姓名顯示一個歡迎信息。這裏隻是簡單地調用了session中的JavaBean(從userBean的tag標識可以看到)。這個Bean是被Controller置於session中,我們接下來可以看到。
Controller
樣例中的controller由一個Servlet構成,代碼參見(Controller.class)。實現了我們應用中的Controller。
這是個簡單的controller,僅僅根據一個request參數(action)決定調用哪一個action。本例中,頁麵將login action作為參數傳遞進來,所以LoginAction被調用。該action實現了一個標準接口(Action),定義了將Request和Response對象作為參數的execute方法。這個action類返回被調用的下一頁的路徑,於是用戶重定向到此頁麵。
LoginAction類從request中獲得username參數,創建一個新的model對象(UserBean),並將其傳至Session,並返回"/welcome.jsp"標識流轉的下一頁麵是welcome.jsp.
Model.
我們示例中的model也很簡單,僅由一個JavaBean構成。代碼參考UserBean.class。
Action的擴展應用
如你所示,這是一個很簡單的Model 2應用,但它可以被在更大程度擴展。比如,我們可以動態配置映射request參數的action,我們也可以具體化controler的流轉控製(比如action可以通過一個配置管理器(configuration manager)來動態獲得需要返回的頁麵,而不是象現在這樣寫死在程序裏)。
然而,事實上有一個現成的框架提供所有這些控製、MVC組裝相關的可配置項,甚至更多。
這個現成的框架就是Struts。
Struts介紹
Struts項目作為一個設想是Craig McClanahan2000年提出的,目標是為利用Java技術開發基於MVC模式的Web應用提供一個標準模式。Struts 1.0在2001年中期被最終發布,現在成為Apache Foundation的Jakarta項目的一部分。Structs應用範圍極廣,可以用在不同的項目,不同的行業(我所見到的從電信到電子商務都有應用實例)。
Struts是一個高度可配置、高度擴展性的MVC框架,我們幾乎可以用它開發任何能想到的用Java技術的Web應用。MVC模式的每一部分在Structs中都有相關對應部分。
Struts的安裝
可以在http://apache.get-software.com/jakarta/struts/binaries/jakarta-struts-1.1.zip下載獲得Struts的最新版本(目前是1.1)。下載後解壓zip文件。發布包中包含了所有開發Struts應用所需的類庫。發布包的Webapps目錄下有一個空白的Struts Web應用(struts-blank.war),它已經包含了一個Web應用的骨架,非常有用,在這個基礎上建立自己的應用顯然對初學者能很快得到成就感。
自己的代碼放在WEB-INF/classes 目錄下,根據自己的需要修改配置文件WEB-INF/struts-config.xml,做到這步,Struts的配置就完成了。現在就擁有了一個完全有效的Struts應用了。
讓我們來看看Struts提供的組件
View層
大多數Struts應用的view層是由JSP組成的。為了使view的開發更加容易,Struts提供了一整套JSP自定義的tag庫。這些tag庫使我們能很容易地提供完全國際化的用戶界麵,這些界麵通常是與Struts應用中的Model組件交互。
通常Web應用的動態前端都是基於HTML表單的,這些應用的用戶需要應用的可靠性得到保證,這樣就需要表單校驗。如果用標準的JSP,記錄表單的內容和從一個JavaBean獲得表單內容簡單乏味而且容易出錯。Structs應用FormBean使表單處理和校驗變得容易。FormBean與Struts的tag庫結合,使帶form的View開發變得容易而自然。
下麵是一個Struts的JSP頁麵樣例。
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head></head>
<body bgcolor="white">
<html:errors/>
<html:form action="/logon">
<table border="0" width="100%">
<tr>
<td>
Username:
</td>
<td>
<html:text property="username"/>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<html:password property="password"/>
</td>
</tr>
<tr>
<td>
<html:submit/>
</td>
<td>
</td>
</tr>
</table>
</html:form>
</body>
</html:html>
從以上JSP樣例可以看出,這與標準的HTML 表單不同。頁麵中沒有雜亂無章的JSP<%>代碼,然而它卻能完成更多的功能。此JSP引入了Struts的HTML tag 庫,它增加了能夠完成收集提供了校驗、錯誤處理、model交互功能的表單。注意<html:errors> tag,它可以顯示model或者controller已經注冊的錯誤。<html:form> tag則創建了一個基於ActionForm對象的HTML表單。上例中表單的action被置於 /login,我們用這個值到配置文件(示例如後)中去找對應的ActionForm。這種映射關係由表單對象的名字和它被存儲的範圍(session,頁麵,應用等等)組成。對象的屬性用<html:text> 、<html:password> tag來表示,構成表單。值得誇耀的好處是,ActionForm被提交時可以自動拾獲對應的表單數據,無須我們操心。