本文介紹Java Web Framework的基本工作原理,和一些常用的開源Web MVC Framework(Struts, Web Work, Tapestry, Echo, JSF, Maverick, SPRing MVC, Turbine, Cocoon, Barracuda)。
Web開發的最重要的基本功是HTTP;Java Web開發的最重要的基本功是Servlet Specification。HTTP和Servlet Specification對于Web Server和Web Framework的開發實現來說,是至關重要的協議規范。
應用和剖析開源Web Framework,既有助于深入把握HTTP & Servlet Specification, 也有助于了解一些現代的B/S Web框架設計思想,如MVC,事件處理機制,頁面組件,IoC,AOP等。在這個現代化的大潮中,即使Servlet規范本身也不能免俗,不斷引入Filter、Listener等現代框架設計模式。同是Sun公司出品的JSF更是如此。
關于MVC模型、項目簡介、配置文件、入門示例等基礎知識,網上已經有大量的重復資料信息,本文不再贅述。
文中會提到一些相關的開源項目,和一些編程思想,如有需要,可以用相關的要害字在網上搜索,獲取基本的背景知識。
本文力圖言簡意賅,突出重點。著重描述其他資料沒有提到、或很少提到的較重要內容,如運行原理、主流用法,相關知識,要害特性等。
Tomcat的Server.xml文件中定義了網絡請求路徑到主機本地文件路徑的映射。比如,<context path="/yourapp" docBase="yourapp_dir/webapp"/>
我們來看一下,一個HTTP Request-Response Cycle的處理過程。
HTTP Request URL一般分為三段:host, context, path。
如http://yourhost/yourapp/en/index.Html這個URL,分為host=yourhost, context=yourapp, path=en/index.html三段。其中,Context部分由request.getContext()獲得,path部分由request.getServletPath()獲得(返回結果是“/en/index.html”)。
yourhost主機上運行的Tomcat Web Server接收到這個URL,根據Context定義,把yourapp這個網絡路徑映射為yourapp_dir/webapp,并在此目錄下定位en/index.html這個文件,返回到客戶端。
假如我們這個URL更換為http://yourhost/yourapp/en/index.jsp,這個時候Tomcat會試圖把yourapp_dir/webapp/en/index.jsp文件編譯成Servlet,并調用運行這個Servlet。
我們再把這個URL更換為http://yourhost/yourapp/en/index.do。
注重,戲劇化的事情就發生在這個時候,Servlet規范中最重要的類RequestDispatcher登場了。RequestDispatcher根據WEB-INF/web.xml配置文件的定義,調用對應的Servlet來處理en/index.do這個路徑。
假設web.xml里面有這樣的定義。
<servlet>
<servlet-name>DispatchServlet</servlet-name>
<servlet-class>yourapp.DispatchServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatchServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
那么,RequestDispatcher會調用yourapp.DispatchServlet類處理這個路徑。
假如web.xml沒有定義對應en/index.do這個路徑的Servlet,那么Tomcat返回“您請求的資源不存在”。
RequestDispatcher用于Web Server中,也可以用于應用程序中進行處理轉向,資源定位。比如,我們在處理en/index.do的代碼中調用,
request.getRequestDispatcher(“cn/index.jsp”).forward(request, response), 就可以轉交另外的資源cn/index.jsp來處理。
幾乎所有的Web Framework都需要定義自己的Dispatch作用的Servlet,并調用RequestDispatcher進行轉向處理。
閱讀Web Framework源代碼,有兩條主要線索,(1)根據web.xml找到對應的Servlet類;(2)搜索包含“RequestDispatcher”詞的代碼文件。
我們看到,request, response 這兩個參數,被RequestDispatcher在各種Servlet之間傳來傳去(JSP也是Servlet)。所以,request的setAttribute()和getAttribute()方法是Servlet之間傳送數據的主要方式。
在MVC結構中,一般的處理流程如下:
處理HTTP Request的基本單位一般稱為Action,是一個比Servlet輕量得多的接口定義,通常只有一兩個方法,如execute(perform), validate等。
我們知道,URL->Servlet映射,定義在Web.xml配置文件里,但MVC框架通常會有另外一個定義URL-> Action映射的配置文件。
入口Dispatcher Servlet根據URL -> Action的映射關系,把請求轉發給Action。
Action獲得輸入參數,調用商業邏輯,并把結果數據和View標識給(Model & View)返回給Dispatcher Servlet。
Dispatcher Servlet根據這個View 標識,定位相應的View Template Path,把處理轉交給View(JSP +TagLib, Velocity, Free Marker, XSL等)。
View一般通過request.getAttribute()獲得結果數據,并顯示到客戶端。至于是誰把結果數據設置到request.attribute里面,有兩種可能:Action或Dispatcher Servlet。
http://struts.apache.org/
Struts是目前用戶群最大、開發廠商支持最多的開源Web Framework。
Struts勞苦功高,為普及MVC框架作出了不可磨滅的貢獻。顯赫的聲望,趨于老化的厚重結構,令Struts成為很多現代Web Framework參照、挑戰的目標。
Struts應用主要包括3件事情: 配置struts-config.xml文件,實現Action類,實現View;還有一些高級擴展用法。下面分別講述。
1. 配置struts-config.xml文件:
Struts支持多級配置文件,具體用法和限制,詳見Struts文檔。這里只討論struts-config.xml主流配置的內容。:-)
(1) URL Path到Action的映射。
如<action path="/LogonSubmit" type="app.LogonAction" ... />
Struts的入口Servlet是ActionServlet。
ActionServlet需要此信息把URL Path調用對應的Action類處理。
在Struts運行期間,一個URL Path,只存在一個對應的Struts Action實例。所有的該URL Path的請求,都經過這同一個Struts Action實例處理。所以Struts Action必須線程安全。
想想看,其實這個要求并不過分,Action只是一個處理程序,不應該保存跨HTTP請求的狀態數據,按理來說,也應該做成線程安全的。
(2) Template Name到View Template Path的映射。
<forward name="sUCcess" path="/pages/Welcome.jsp"/>
Action類返回一個Template Name,ActionServlet根據這個Template Name獲得對應的View Template Path,然后調用
request.getRequestDispatcher(“View Template Path”),把處理轉向路徑對應的Servlet。在這個例子中,是轉向/pages/Welcome.jsp編譯后的Servlet。
我們來看一個一個Velocity的例子。
<include name="success" path="/pages/Welcome.vm"/>
web.xml的定義如下
<servlet>
<servlet-name>velocity</servlet-name>
<servlet-class>org.apache.velocity.tools.view.servlet.VelocityViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>velocity</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
這時,request.getRequestDispatcher(“/pages/Welcome.vm”)會調用VelocityViewServlet,由VelocityViewServlet負責裝并驅動運行/pages/Welcome.vm這個模板文件。
這里面有一個問題,假如調用的是DispatchRequester.include()
新聞熱點
疑難解答