1. 程式人生 > >SpringMVC應用程式架構----高階特性

SpringMVC應用程式架構----高階特性

Web 應用與MVC

目前比較好的MVC,老牌的有StrutsWebwork。新興的MVC 框架有Spring MVCTapestryJSF等。這些大多是著名團隊的作品,另外還有一些邊緣團隊的作品,也相當出色,如DinamicaVRaptor等。

這些框架都提供了較好的層次分隔能力。在實現良好的MVC 分隔的基礎上,通過提供一些現成的輔助類庫,同時也促進了生產效率的提高。

如何選擇一個合適的框架?什麼是考量一個框架設計是否優秀的標準?很難定奪的問題。旁觀各大論壇中鋪天蓋地的論戰,往往在這一點上更加迷茫。

從實際Web產品研發的角度而言(而非純粹設計上,擴充套件性上,以及支援特性上的比較),目前

Struts 也許是第一選擇。作為一個老牌MVC FrameworkStruts 擁有成熟的設計,同時,也擁有最豐富的資訊資源和開發群體。換句實在點的話,產品基於Struts 構建,如果公司發生人事變動,那麼,找個熟悉Struts的替代程式設計師成本最低。

從較偏向設計的角度出發,WebWork2 的設計理念更加先進,其程式碼與Servlet API 相分離,這使得單元測試更加便利,同時系統從BS結構轉向CS介面也較為簡單。另外,對於基於模板的表現層技術(VelocityFreemarkerXSLT)的支援,也為程式設計師提供了除JSP之外的更多的選擇(Struts也支援基於模板的表現層技術,只是實際中不太常用)。而對於

Spring而言,首先,它提供了一個相當靈活和可擴充套件的MVC實現,與WebWork2相比,它在依賴注入方面、AOP 等方面更加優秀,但在MVC 框架與底層構架的分離上又與Webworks 存在著一定差距(Spring MVC Servlet API 相耦合,難於脫離Servlet容器獨立執行,在這點的擴充套件性上,比Webwork2稍遜一籌)。

我們還要注意到,Spring對於Web應用開發的支援,並非只限於框架中的MVC部分。即使不使用其中的MVC實現,我們也可以從其他元件,如事務控制、ORM模板中得益。同時,Spring也為其他框架提供了良好的支援,如我們很容易就可以將Struts

Spring 甚至WebWorkSpring 搭配使用(與WebWork 的搭配可能有些尷尬,因為兩者相互覆蓋的內容較多,如WebWork中的依賴注入機制、AOP機制等與Spring中的實現相重疊)。因此,對於SpringWeb應用中的作用,應該從一個更全面的角度出發。第一個SpringMVC例項:下面的例項,實現了一個常見的使用者登入邏輯,即使用者通過使用者名稱和密碼登入,系統對使用者名稱和密碼進行檢測,如果正確,則在頁面上顯示幾條通知資訊。如果登入失敗,則返回失敗介面。
(
示例中,表示層以JSP2.0實現。)
出於簡潔考慮,這裡的使用者名稱/密碼檢測以及通知資訊的生成均在程式碼中以硬編碼實現。首先來看登入介面:對應的index.html:
<form action="login.do" method="post">
<table>
<tr>
<td>
使用者名稱:</td>
<td><input type="text" name="username" /></td>
</tr>

<tr>
<td>
密碼:</td>
<td><input type="password" name="password"></td>
</tr>

<tr>
<td colspan="2" align="right"><input type="submit" value="
提交" /></td>
</tr>
</table>
</form>

MVC 關鍵流程的第一步,即收集頁面輸入引數,並轉換為請求資料物件。這個靜態頁面提供了一個基本的輸入介面,下面這些輸入的資料將被髮送至何處,將如何被轉換為請求資料物件?現在來看接下來發生的事情:當用戶輸入使用者名稱密碼提交之後,此請求被遞交給Web 伺服器處理,上面我們設定form提交目標為"/login.do",那麼Web伺服器將如何處理這個請求?顯然,標準Http 協議中,並沒有以.do 為字尾的服務資源,這是我們自己定義的一種請求匹配模式。此模式在web.xml中設定:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
 xmlns="
http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 <servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/Config.xml</param-value>
</init-param>
 </servlet>

 <servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
 </servlet-mapping>

</web-app>
Config.xml
配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"

<beans>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
</bean>

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/login.do">LoginAction</prop>
</props>
</property>
</bean>

<bean id="LoginAction" class="com.hit.action.LoginAction">
<property name="commandClass">
<value>com.hit.action.LoginInfo</value>
</property>

<property name="fail_view">
<value>/WEB-INF/loginFail.jsp</value>
</property>

<property name="success_view">
<value>/WEB-INF/loginSuccess.jsp</value>
</property>
</bean>
</beans>

View ResolverviewClass引數這裡我們使用JSP頁面作為輸出,因此,設定為:
org.springframework.web.servlet.view.JstlView
其餘可選的viewClass還有:
Ø org.springframework.web.servlet.view.freemarker.FreeMarkerView
(用於基於FreeMarker模板的表現層實現)
Ø org.springframework.web.servlet.view.velocity.VelocityView
(用於基於velocity模板的表現層實現)等。


“urlMapping”
關係對映可以看到,這裡我們將“/login.do”請求對映到處理單元LoginAction<props>節點下可以有多個對映關係存在,目前我們只定義了一個。

LoginAction定義這裡定義了邏輯處理單元LoginAction 的具體實現,這裡,LoginAction 的實現類為com.hit.action.LoginAction

LoginAction的請求資料物件
commandClass
引數源於LoginAction 的基類BaseCommandControllerBaseCommandControlle 包含了請求資料封裝和驗證方法( BaseCommandController.bindAndValidate ),它將根據傳入的HttpServletRequest構造請求資料物件。這裡我們指定commandClass com.hit.action.LoginInfo,這是一個非常簡單的Java Bean,它封裝了登入請求所需的資料內容:
package com.hit.action;

public class LoginInfo {

 private String username;
 private String password;
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }

}

Spring會根據LoginActioncommandClass定義自動載入對應的LoginInfo例項。之後,對Http 請求中的引數進行遍歷,並查詢LoginInfo 物件中是否存在與之同名的屬性,如果找到,則將此引數值複製到LoginInfo物件的同名屬性中.請求資料轉換完成之後,我們得到了一個封裝了所有請求引數的Java 物件,並將此物件作為輸入引數傳遞給LoginAction

返回檢視定義對於這裡的LoginAction 而言,有兩種返回結果,即登入失敗時返回錯誤介面,登入成功時進入系統主介面。對應我們配置了fail_viewsuccess_view兩個自定義引數。之後,Resolver 會將LoginAction的返回資料與檢視相融合,返回最終的顯示介面。

LoginAction.java:
public class LoginAction extends SimpleFormController {

 private String success_view;
 private String fail_view;

 public String getFail_view() {
  return fail_view;
 }

 public void setFail_view(String fail_view) {
  this.fail_view = fail_view;
 }

 public String getSuccess_view() {
  retiurn success_view;
 }

 public void setSuccess_viiew(String success_view) {
  this.success_view = success_view;
 }

 @Override
 protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response,
Object obj,
BindException ex) throws Exception {
  request.setAttribute("message", "success");
  return new ModelAndView(this.getSuccess_view());
 }


}

其中: onSubmit方法我們在子類中覆蓋了父類的onSubmit方法;而onSubmit方法用於處理業務請求。負責資料封裝和請求分發的Dispatcher,將對傳入的HttpServletRequest進行封裝,形成請求資料物件,之後根據配置檔案,呼叫對應業務邏輯類的入口方法(這裡就是LoginAction)的onSubmit()方法,並將請求資料物件及其他相關資源引用傳入。
onSubmit
方法包含了兩個或者四個引數:Object objBindException ex前面曾經多次提到請求資料物件,這個名為objObject型引數,正是傳入的請求資料物件的引用。
BindException ex
引數則提供了資料繫結錯誤的跟蹤機制。它作為錯誤描述工具,用於向上層反饋錯誤資訊。Spring MVC中,BindException將被向上層表現層反饋,以便在表現層統一處理異常情況(如顯示對應的錯誤提示)