程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> J2EE表現層設計思考

J2EE表現層設計思考

編輯:關於JAVA

設計表現層時需要考慮的幾個問題

開發者在設計表現層時,可以使用不同的模型,這時需要考慮一些相關的設計問題。這些問題和模型關系的緊密程度也各有不同,它們可以影響系統的各個方面,包括有安全、數據完整性、可管理性和擴展性。雖然這些設計問題大部分都可以用模型的形式表示,但我們不打算這樣做,因為這樣更為抽象,我們選擇以非正式的文檔形式表示。我們只是根據不同的模型,將每個需要考慮的問題列出來。

Session管理

用戶Session指的是跨越一個客戶和服務器多個請求間的一個對話。我們將在以下部分根據用戶Session的概念討論這個問題。

客戶端的Session狀態

在客戶端保存Session的狀態指的是將Session的狀態串行化並且嵌入到返回給客戶的HTML頁面中。

在客戶端保存Session的狀態有這以下的好處:

. 它實現起來相對容易

. 在保存少量的狀態信息時,它工作得很好

此外,這個策略還消除了跨越多個服務器復制狀態的問題,例如多個服務器間實現負載均衡時就會遇到這種情況。

在客戶端保存Session狀態通常有兩個方法--HTML的隱藏字段和HTTP cookies--我們將在下面討論這些策略。第三個策略則是在每個頁面的URL中嵌入Session狀態信息,例如<form action=someServlet?var1=x&var2=y method=GET>。雖然第三個方法比較少見,但它也有著其它兩個方法的許多限制。

HTML的隱藏字段(HTML Hidden Fields)

雖然這個方法實現起來相對容易,不過使用HTML隱藏字段在客戶端保存Session狀態仍然有著許多的缺點。這些缺點在保存大量的狀態時尤為突出。保存大量的狀態將會對性能有很大的影響。因為每次發出請求和響應時,都需要在網絡中傳送這些狀態信息。

此外,當你利用隱藏的字段來保存Session狀態時,這些持久的狀態值只能是字符串值,因此所有的對象引用都必須被“字符串化”,而這些信息除非經過特別的加密,否則都是以明文的形式顯示在HTML的源代碼中。

HTTP Cookies

與隱藏字段的方法一樣,使用HTTP Cookies的方式也是相對簡單的。不幸的是,這兩個方法有著許多相同的缺點。特別是,在保存大量的狀態信息時將會對性能產生很大的影響,因為在每次的請求和響應時,都必須在網絡上傳送全部的Session狀態信息。

在客戶端保存Session狀態時,我們也會遇到大小和類型的局限問題。cookie headers的大小是有限制的,這樣就限制了可以被持久保存的數據量,而且和隱藏字段的方法一樣,當你使用cookies來保存Session狀態時,這些持久的狀態信息只能使用字符串值。

在客戶端保存Session狀態會帶來的安全問題

當你在客戶端保存Session狀態時,你必須考慮到由此帶來的安全問題。如果你不想數據暴露給客戶端,你就需要一些方法來加密數據,從而保證數據的安全。

雖然在客戶端保存Session狀態相對容易實現,不過它有著很多的缺點,這些都要我們花費時間去解決。對於需要處理大量數據的項目,特別是企業的系統,使用這種方式是得不償失的。

表現層的Session狀態

當Session狀態保存在服務器端時,它使用一個Session ID得到,並且會一直保持住,直到發生以下的情形:

. 一個預定義的Session超時發生了

. Session被手動設置為無效

. 狀態由Session中移除

要注意的是服務器關閉後,一些內存中的Session管理機制可能不能恢復。

很明顯,對於要保存大量Session狀態的應用,將它們的Session狀態放在服務器是更好的。當狀態被保存在服務器上時,你不會有客戶端Session管理的大小和類型限制。此外,還避免了由此帶來的安全問題,而且也不會遇到由於在每個請求間傳送Session狀態帶來的性能影響。

使用該方式,你可以更加靈活地作處理,並且便於擴展和提高性能。

如果你在服務器上保存Session狀態,你必須要決定如何使該狀態信息被每個服務器得到,即你運行該應用的服務器。如果群集的軟件是運行在負載均衡的硬件上,那麼就要處理這個Session狀態的復制問題,這是一個多維的問題,不過,眾多的應用服務器現在都提供了各種各樣的解決方案。也就是說,在應用服務器的級別上有解決的方法。其中的一個方法是保證用戶只與一個服務器打交道,它在流量管理軟件上用得比較多,例如Resonate [Resonate]的軟件,在用戶的Session中,該用戶發出的每個請求都會被路由到同一個服務器處理。這種方式也被稱為server affinity。

另一個可選的方式是在商業層或者資源層保存Session狀態。企業JavaBeans組件可用來在商業層保存Session的狀態,而一個關系數據庫則可用在資源層。

控制客戶訪問

有很多時候我們都要限制或者控制客戶端訪問某些應用資源。下面我們就來討論其中兩種這樣的情形。

限制或者控制客戶訪問的一個原因是防止一個視圖或者部分的視圖被一個客戶直接訪問。這個問題會發生在以下情況,例如僅有注冊或者登陸後的用戶才可允許訪問一個特別的視圖,或者是根據用戶的角色限制用戶訪問部分的視圖。

在描述過這個問題後,我們將討論第二種情況,它和控制應用中一個用戶的流程有關。後者的討論和重復的form提交有關,因為多次提交將會導致不必要的重復事務。

控制視圖訪問

在一些情況下,資源被限制為完全不允許某些用戶訪問。有幾個方法可以做到這一點。一個方法是加入應用邏輯到處理控制器或者視圖的程序中,禁止某些用戶訪問。另一個方案是設置運行時的系統,對於一些資源,僅允許經由另一個應用資源內部調用。在這種情形,對於這些資源的訪問必須被通過另一個表現層的應用資源進行,例如一個servlet控制器。對於這些受限制的資源不允許通過一個浏覽器直接調用。

處理這個問題的一個常見方法是使用一個控制器來作為該類訪問控制的一個委托者。另一個常見的方式是在一個視圖中置入一個保護設置。我們這裡主要討論基於視圖的控制策略。在考慮選擇何種方式來控制訪問之前,我們首先來描述一下這些策略。

在視圖中置入保護邏輯

對於在一個視圖的處理中置入一個保護邏輯,有兩個常見的應用。一個是防止訪問整個的資源,而另一個是限制訪問部分的資源。

在每個視圖中包含一個All-or-Nothing保護

在一些情況下,置入到視圖處理代碼中的邏輯以all-or-nothing的模式允許或者拒絕訪問。也就是說,這個邏輯限制某個特別的用戶訪問一個特別的視圖。通常這一類型的保護最好封裝到一個中央化的控制器中,這樣便於集中化管理。如果只有很少的頁面需要防護,那麼可以使用這個策略。通常這個情形都是發生在一個非技術人員需要更新網站一小部分的靜態文件。如果客戶仍然需要登陸到網站來浏覽這些頁面,那麼只需要在每個頁面的頂部加入一個自定義的tag(標記)就可以做到控制訪問。如3.1的例子所示。

例子3.1 在每個視圖中包含一個All-or-Nothing保護

<%@ taglib uri="/WEB-INF/corej2eetaglibrary.tld"
prefix="corePatterns" %>
<corePatterns:guard/>
<HTML>
.
.
.
</HTML>

給視圖的某些部分加入保護

在其它情況下,置入到視圖處理代碼的邏輯可拒絕訪問一個視圖的某些部分。這個策略可以和上面的all-or-nothing策略一起使用。為說明這一點,我們這裡使用控制訪問一個建築物中的一個房間作類比。all-or-nothing的保護策略告訴用戶是否可以進入房間,而第二個保護策略則是告訴用戶在進入房間後,允許他們看到什麼東西。以下就是一些你可以利用這個策略的例子。

根據用戶的角色決定是否顯示視圖的某些部分

根據用戶的角色,視圖的某部分可能不顯示。例如,一個經理在收看管理信息時,他可以訪問到其員工的子視圖,而作為一個員工,他只可以看到自己組織的信息,而不可以訪問其它信息,如例子3.2所示。

例子3.2 根據用戶的角色,部分的視圖不顯示

<%@ taglib uri="/WEB-INF/corej2eetaglibrary.tld"
prefix="corePatterns" %>
<HTML>
.
.
.
<corePatterns:guard role="manager">
<b>This should be seen only by managers!</b>
<corePatterns:guard/>
.
.
.
</HTML>

根據系統的狀態或者錯誤情形不顯示部分的視圖

根據系統的環境,顯示的規劃可以被修改。例如,如果用戶使用的是一個單CPU的硬件設備,那麼使用多個CPU的部分設備就可以不顯示。

根據配置控制資源訪問

要限制某個客戶直接訪問一個特別的視圖,你可以配置表現層只有通過內部的資源才可以訪問到這些資源,例如一個使用RequestDispatcher的servlet控制器。此外,你還可以使用Web容器中內置

的安全技術,根據servlet2.2或者以後的規范。安全限制被定義在稱為web.xml的配置描述文件中(deployment descriptor)。

basic和form-based的認證方法在Servlet規范中也有描述。在此我們不打算重復這個規范,你可以到以下網址去查看當前規范的細節(http://java.sun.com/products/servlet/index.html)。

你已經明白了加入安全限制到你的應用時會有什麼用處,我們簡要討論了這個問題並且介紹了如何通過配置令它和all-or-nothing保護相關。最後,我們描述了一個簡單和常用的方法作為all-or-nothing保護,以限制一個資源的訪問。

通過安全限制保護資源

應用或許被配置在一個安全限制中,而這個安全限制允許使用編程的方法根據用戶的角色來控制訪問。資源可以被某些角色的用戶訪問,並且禁止其它的角色訪問。另外,某個視圖的一部分也可以根據用戶的角色來限制訪問。如果某些資源完全禁止全部的直接浏覽器請求,例如上面all-or-nothing情景中提到的一樣,那麼這些資源可以只允許一些安全角色訪問,而這些安全角色不分配給任何一個用戶。這樣只要不分配這個安全角色,那麼以這種方式配置的資源將禁止所有的浏覽器直接訪問。例子3.3就是一個web.xml配置文件的一部分,它定義了一個安全的角色以限制直接的浏覽器訪問。

角色的名字是“sensitive”,受限制資源的名字是sensitive1.jsp, sensitive2.jsp和sensitive3.jsp。除非一個用戶或者組被分配到“sensitive”角色,否則這些客戶都不可以直接訪問這些JSP頁面。不過,由於內部的請求並不受這些安全的限制,一個初始時由某servlet控制器處理的請求將會導向到這些受限制的頁面,這樣它們就可以間接訪問這些JSP頁面。

最後,要注意的是,不同廠家的產品在實現Servlet2.2版本的規范時,在這個方面有些不兼容的現象。不過支持Servlet2.3的服務器則沒有這個兼容性的問題。

例子 3.3 通過不分配安全角色提供All-or-Nothing控制

<security-constraint>
<web-resource-collection>
<web-resource-name>SensitiveResources </web-resource-name>
<description>A Collection of Sensitive Resources </description>
<url-pattern>/trade/jsp/internalaccess/ sensitive1.jsp</url-pattern>
<url-pattern>/trade/jsp/internalaccess/ sensitive2.jsp</url-pattern>
<url-pattern>/trade/jsp/internalaccess/ sensitive3.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>sensitive</role-name>
</auth-constraint>
</security-constraint>

設置資源保護的一個簡單方法

有一個簡單和常見的方法可以限制一個客戶直接訪問某個資源,例如JSP。和3.3的例子一樣,這個方法無需修改任何的配置文件。這個方法只是需要將資源放置在Web應用的/WEB-INF/目錄下。例如,要防止浏覽器直接訪問一個稱為info.jsp的視圖,我們假設這個文件是屬於一個名字為securityissues的Web應用。我們可以將該JSP文件放在以下的子目錄:/securityissues/WEB-INF/internalaccessonly/info.jsp。

對於/WEB-INF/目錄及其子目錄是禁止浏覽器直接訪問的,因此info.jsp也不可以直接訪問。不過,如果需要,一個控制器servlet仍然可以導向到這個資源。這種控制使用的是all-or-nothing的方式,因為以這種方式配置的資源都完全禁止浏覽器直接訪問。

重復的Form提交

用戶使用浏覽器時,可以經常使用向後的按鈕,因此就有可能重復提交一個他們已經提交過的form,這樣就會帶來一個重復事務處理的問題。同樣,一個用戶也可能在接收到一個確認的頁面之前按下停止的按鈕,接著再次提交同一個form。對於這些情況,我們都想跟蹤並且禁止這些重復的提交,我們可以使用一個控制servlet來提供一個控制點,以解決這個問題。

同步記號(Synchronizer (or Dvu) Token)

這個策略是為了解決重復的form提交問題。一個同步的記號被設置在一個用戶的Session中,並且包含在返回到客戶的每一個form中。當form被提交時,form中的同步標記就和Session中的同步標記作對比。在form首次提交的時候,這兩個標記應該是一樣的。如果標記不一樣,那麼該form就會禁止提交,一個錯誤就會返回給用戶。在用戶提交一個form時,如果按下浏覽器中的後退按鈕並嘗試重新提交同一個form時,標記就會出現不匹配的現象。

另一方面,如果兩個標記值匹配,那麼我們就可以確信整個流程是正確的。在這種情況下,Session中的標記值就會被修改為一個新的值,同時允許提交該form。

你也可以使用這個策略來控制對某些頁面的直接訪問,就好象上面資源保護中描述的一樣。例如,假設一個用戶將某個應用的頁面A收藏到收藏夾中,而頁面A只允許通過頁面B和C訪問。當用戶直接通過收藏夾來訪問頁面A,這時頁面的訪問順序就是不正確的,這樣同步標記將處在一個不同步的狀態,或者它根本就不存在。不論怎樣,訪問都被禁止了。

驗證

通常我們都希望同時在客戶和服務器端進行驗證。雖然客戶端的驗證處理看來沒有服務器端驗證那樣專業,不過它可以提供高級別的檢查,例如驗證form中的某個字段是否為空。服務器端的驗證通常要廣泛得多。雖然在一個應用中,兩種類型的處理都是適當的,不過這裡不建議只使用客戶端的驗證。這樣做的一個主要原因是由於客戶端的驗證是使用客戶端的腳本語言的,用戶可以在任何時候通過設置,從而跳過這些腳本。

這裡不打算很詳細地討論驗證的策略。我們只是在這裡提及一下這是一個在設計系統時需要考慮到的問題,如果你想更深入地了解,你可以參考現有的文獻。

在客戶端驗證

輸入的驗證在客戶端進行。通常這個操作都是通過嵌入的腳本代碼例如JavaScript進行。上面已經提到,客戶端的驗證是服務器端驗證的一個補充,不過不應該獨立使用。

在服務器端驗證

輸入的驗證在服務器端進行。有幾個典型的策略可用作服務器端驗證。這些策略是Form-Centric Validation(以Form為中心的驗證)和validation based on abstract types(基於抽象類型的驗證)。

Form-Centric Validation

Form-Centric Validation的策略強迫一個應用包含許多的方法來驗證form各部分的狀態。典型地,這些方法依據其包含的邏輯,都是交迭的,這樣不利於重新使用和模塊化。一個驗證的方法都是和用戶某個特定的form相關,沒有共同的代碼來處理常見的操作,例如必填的字段或者只可以使用數字的字段。在這種情況下,當某個字段被用在多個不同的form,並且是一個必填的字段時,它都是在應用中獨立處理的。這個策略實現起來相對容易,並且效率也高,不過當應用變大時,就會帶來重復代碼的問題。

要提供一個更靈活的、可重用的和易於維護的方法,數據模型應該作更大的抽象。這個方式就是下面提到的“根據抽象類型來驗證,form-centric驗證的例子見例子3.4。

Example 3.4 Form-Centric Validation
/**If the first name or last name fields were left
blank, then an error will be returned to client.
With this strategy, these checks for the existence
of a required field are duplicated. If this valid-
ation logic were abstracted into a separate component,
it could be reused across forms (see Validation Based
on Abstract Types strategy)**/
public Vector validate()
{
Vector errorCollection = new Vector();
if ((firstname == null) || (firstname.trim.length() < 1))
errorCollection.addElement("firstname required");
if ((lastname == null) || (lastname.trim.length() < 1))
errorCollection.addElement("lastname required");
return errorCollection;
}

抽象類驗證

這個方法可應用在客戶端或者服務器端,不過在一個基於浏覽器或者瘦客戶端的環境下,最好應用在服務器端。

輸入和限制的信息由模型狀態中抽象出來並且放到一個通用的架構中。這樣將模型的驗證和模型正在使用的應用邏輯分離開來,從而減少了它們的耦合。

模型驗證通過將元數據及限制和模型狀態作對比進行。模型的元數據和限制通常可以通過一些簡單的數據存儲訪問到,例如一個屬性文件。這種方法的好處是系統更通用了,因為它將狀態和限制的信息由應用邏輯中分離出來。

例如有一個組件或者子系統封裝驗證的邏輯,這些邏輯包括判斷一個字符串是否是空的,一個數字的輸入在某個范圍,或者是一個格式化為某種方式的字符串等。當不同的應用組件需要驗證某個模型的不同方面時,每一個組件並不需要寫自己的驗證代碼。取而代之的是,使用集中式的驗證技術。集中式的驗證技術可以通過一些方式設置,例如通過編程,一些發生器或者通常聲明、使用配置文件等。

這樣驗證的技術就更加通用,它集中在模型的狀態和它的需求,而與應用的其它部分無關。使用這個方法的一個缺點是效率和性能要受到影響,而且,通常更通用的方法,雖然功能更強大,但是理解和維護起來有點難懂。

以下是一個例子。一個使用XML的配置文件描述了各種的驗證,例如“必填的字段”,“要求全部是數字的字段”等。此外,可以設計每個驗證的管理類。最後,一個影射將HTML表格的值和某類特別的驗證對應起來。驗證某個特定字段的例子代碼如例子3.5所示。

例子 3.5 Validation Based on Abstract Types

//firstNameString="Dan"
//formFieldName="form1.firstname"
Validator.getInstance().validate(firstNameString, formFieldName);

Helper Properties--完整性和一致性

JavaBean Helper類通常是用來保存一個客戶請求傳送過來的中間狀態。JSP的運行引擎提供了一個技術,可以自動地將這些參數值由一個servlet請求對象拷貝到這些JavaBean的helper對象的屬性中。JSP語法如下所示:

<jsp:setProperty name="helper" property="*"/>

上面的語句告訴JSP引擎將所有匹配的參數值拷貝到一個JavaBean的相應屬性中(這個JavaBean的名字是“helper”),如例子3.6所示。

例子3.6 Helper Properties - A Simple JavaBean Helper

public class Helper
{
private String first;
private String last;
public String getFirst()
{
return first;
}
public void setFirst(String aString)
{
first=aString;
}
public String getLast()
{
return last;
}
public void setLast(String aString)
{
last=aString;
}
}

那麼怎樣才算匹配呢?如果一個request參數的名字和類型和helper bean的屬性一樣,那麼就認為它們是匹配的。通常都會將每個參數和每個bean屬性的名字及bean屬性的setter方法的類型作比較。

雖然這個技巧非常簡單,不過它可以產生一些令人迷惑的東西。首先,要注意的如果request參數的值是空的話那將會怎樣的呢?許多開發者可能認為當一個request參數是一個空的String時,如果它和一個bean屬性匹配,將會令該bean屬性接收一個空的String值或Null。實際上在這種情況下,結果是不會修改匹配的bean屬性。還有,由於JavaBean helper對象是跨越多個請求重用的,這種含糊的做法將令數據值不完整和不正確。圖3.1展示了這類技巧會帶來的問題。

***************圖3.1***************

請求1包含有名字為“first”和“last”的參數值,並且這些值設置了相應的bean屬性。請求2僅包含有“last”參數的值,因此只設置了bean中的其中一個參數,而“first”參數的值則沒有變化。---www.bianceng.cn。它並沒有設置為一個空字段串或者是null,這是由於在請求的參數中並沒有值。如3.1的圖所示,如果bean的值在請求間並沒有手動復位,這是將會帶來不一致的問題。

在設計你的應用時,要考慮的另一個問題是當form中的項目沒有選擇的時候,HTML form接口是如何處理的。例如,當一個form擁有多個checkbox,在沒有選擇任何的checkbox時,服務器端的值是不會被清空的。當request對象由這個接口產生時,在request對象中就沒有包含相應的checkbox參數。因此,這些checkbox相關的參數值都不會發送到服務器端(完整的HTML規范,見http://www.w3.org/)。

由於沒有參數值傳送到服務器,所以如上所述,在使用<jsp:setProperty> 時,匹配的bean屬性將保持不變。在這種情況下,除非開發者手動修改這些值,否則應用中將有可能出現不一致和不正確的數據值。一個簡單的解決方法是在每個請求間復位所有JavaBean的狀態值。

設計表現層時需要避免的壞習慣

所謂的壞習慣,指的是未達到最優化的方案,它們與設計模式的建議是沖突的。當我們將模式和好習慣記錄下來時,我們就會自然地拋棄掉那些未達到最優化的習慣。

在這裡,我們簡單談一下與表現層相關的壞習慣。

在每個部分,我們都簡要描述一下壞習慣,並且提供相關的指引,包括有設計問題,refactoring和模式等,提供進一步的信息和更好的選擇。我們並不會非常深入地討論每個壞習慣,這裡只是點到即止,有興趣的可繼續深入研究。

多個視圖中使用控制代碼

問題摘要

自定義tag helper可以包含在JSP視圖的頂部,以執行訪問控制和其它類型的檢查。如果大量的視圖包含有類似的helper引用,維護這些代碼將會變的非常困難,因為修改可以發生在多個地方。

解決方法:

修改控制代碼,使用一個controller和相關的Command helpers。當需要在多個地方包含類似的控制代碼時,例如只有一部分的JSP視圖禁止一些用戶訪問的時候,將這個工作通過一個可重用的helper類完成。

在商業層暴露表現層的數據結構

問題摘要

表現層的數據結構,例如HttpServletRequest,應該被限制到表現層上。如果將這些細節放到商業層或者其它層中,將增加這些層間的耦合,這樣就會減少可利用服務的重用性。如果商業服務的方法接受一個HttpServletRequest類型的參數,這樣使用這個服務的客戶(即使是那些非Web上的客戶)都必須將它們的請求狀態封裝到一個HttpServletRequest對象中。此外,商業層的服務需要知道如何與這些表現層的數據結構交互,從而令商業層的代碼變得復雜,並且增加了層間的耦合。

解決方法:

不讓表現層的數據結構和商業層共享,而是拷貝相關的狀態到一個更常見的數據結構中並且再共享。你也可以選擇由表現層數據結構中將相關的狀態分離出來,作為獨立的參數共享。

在域對象暴露表現層的數據結構

問題摘要

將諸如HttpServletRequest的請求處理數據結構和域對象共享,這樣將不必要地增加了應用中兩個不同方面的耦合。域對象應該是可重用的組件,如果它們的實現依賴協議或者層相關的細節,它們可重用的機會就會減少,而且,維護和調試高耦合的應用更加困難。

解決方法:

不通過傳送一個HttpServletRequest對象作為一個參數,而是拷貝request對象的狀態到一個更為常用的數據結構中,並且將這個對象共享給域對象。你也可以選擇由HttpServletRequest對象中將相關的狀態分離出來,並且將每一個的狀態作為一個獨立的參數提供給域對象。

允許重復的Form提交

問題摘要

浏覽器客戶環境的其中一個缺點是對缺少對客戶浏覽某個應用時的控制。一個用戶可能提交了一個訂單,這個交易將會導致由一個信用卡帳號中扣除費用,並且將產品運送到客戶手中。在接收到確認頁面後,如果用戶點擊後退的按鈕,同一個form將會再次提交。

解決方法

這個問題的解決方法上面已經提到,這裡不再詳述

直接暴露敏感的資源給客戶訪問

問題摘要

在企業環境中,安全是其中一個最重要的問題。如果某些信息沒有必要讓一個客戶直接訪問到,那麼這些信息應該保護起來。對於特別的配置文件,屬性文件,JSP或者class文件,如果不作一些保護,那麼客戶將可以不經意或者故意地接收到敏感的信息。

解決方法

關於保護敏感資源的方法,上面已經提到。

錯誤地認為<jsp:setProperty>將會復位Bean屬性

問題摘要

<jsp:setProperty>標准標簽可將request的參數值拷貝到同名的JavaBean helper屬性中,不過,當參數的值為空時,得到的結果是很容易使人迷惑的。例如,一個值為空的參數將會被忽略,但很多開發者都錯誤地認為匹配的JavaBean屬性將會得到一個null或者空的字符串值。

解決方法:

在使用<jsp:setProperty>標簽時,不要只是想當然,在使用前,你應該初始化bean屬性。

創建過大的控制器(Controller)

問題摘要

對於多個JSP視圖中重復使用的控制代碼,在很多時候都會放到一個控制器中。如果太多的代碼被加入到一個控制器中,那麼它就會變得很龐大並且難以維護、測試和調試。例如,對一個servlet控制器進行單元測試,特別是一個“臃腫的控制器”,相對於測試一個獨立的和HTTP協議無關的helper類,將會復雜得多。

解決方法

在處理一個請求時,控制器通常都是首先處理的地方,不過它應該也是一個委托點,與其它的控制類一起工作。可以使用Command對象來封裝控制器委托的控制代碼。測試這些獨立於Servlet引擎的JavaBean command對象要容易得多,因為它需要測試的模塊代碼更少。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved