http://dev2dev.bea.com.cn/techdoc/20031027.html?S_TACT=105AGX52&S_CMP=tag-csdn
簡介
頁面流提供了一種方便構建Web應用業務和導航邏輯的編程模型。爲了顯示和修改頁面流動作所收集的數據,WebLogic Workshop 8.1 數據綁定框架將用戶界面中的NetUI JSP標籤綁定到Web應用數據上。兩者相互結合爲構建基於Web的用戶界面提供了一種令人矚目的開發模型。
數據綁定是一個重要主題;這裏我們將介紹用於綁定、顯示、更新數據的表達式語言和JSP標籤;並將演示如何創建一個簡單的表單。本文假定讀者對基本頁面流和JSP程序設計較爲熟悉。文中用到的所有代碼都可以從附帶的下載文件Web application (1.4 MB)中獲得。
參與者
綁定UI到數據的過程需要三個參與者--業務對象/數據、NetUI JSP標籤庫、表達式語言。業務對象中含有需要綁定到JSP頁面的數據。JSP標籤以特定視圖(只讀或可更新)的方式在Web瀏覽器中繪製數據,而表達式語言則將兩者粘合在一起,從而可以通過JSP標籤引用業務對象的屬性。藉助三個參與者的實例,Workshop開發人員可以用靈活且優雅的方式創建用於顯示、更新、及創建數據的用戶界面。
整篇文章我們都會用到一個定義了字段和屬性的JavaBean,屬性更適合說明數據是如何綁定到不同類型之上的。該表單的一部分如下;其中定義了一個公共屬性name 和一個公共字段eMail。可以把該類看作一個針對簡單Web頁面的業務對象,該Web頁面演示瞭如何綁定到表單的屬性。
public class Customer { public String eMail = ""; private String name; public String getName() { return this.name; } . . . } [binding/Controller.jpf] |
URL 也是該bean的一個屬性。除此之外,同一頁面流中還定義了一個LocationInfo 類,它暴露了可以進行數據綁定的複雜類型。
爲了更快將讀者引進門,我們假定代表用戶"Dave Smith"的Customer對象已經存在,並且可以通過String類型的關鍵字"customer"在request的屬性映射中進行訪問。這個Customer的姓名可以藉助JSP的NetUI標籤顯示在Web頁中。
Customer Name: <netui:label value="{request.customer.name}"/> [binding/simple.jsp] |
它在Workshop JSP 設計器中顯示如下:
Customer Name: {request.customer.name} |
並生成如下的HTML輸出:
Customer Name: <span>John Smith</span> |
下面我們將從整體上更進一步分析這個例子和表達式。
表達式語言
表達式語言使得Workshop開發人員能夠使用一種簡單的語法在JSP頁面中引用業務對象的數據。通常,一個表達式引用業務對象上的一個或一系列屬性,從而可以唯一標識JSP標籤所綁定的數據。在以上例子中,表達式{request.customer.name}引用Customer JavaBean中的name 屬性,保存在request中的該JavaBean被稱作"customer"。
在JSP標籤屬性中,表達式分別以'{' 和'}'作爲開始和結束標記。標籤探測一個屬性是否是表達式、或者其中是否包含表達式,從而對屬性進行求值。
一個表達式含有兩個獨立的部分--數據綁定上下文:在其中進行表達式求值;屬性:它是表達式求值返回的結果。在表達式{request.customer.name}中, request是綁定上下文,它引用JSP頁面request的屬性映射。表達式剩下的部分用來引用唯一的對象屬性。"customer"標識符用來在request的屬性映射中查找相關對象,name標識符用來獲取Customer 對象上的JavaBean 屬性name。從功能上講,該表達式等同於以下語句:
String name = ((Customer)request.getAttribute("customer")).getName(); |
同樣是引用相同的數據,表達式語法更爲簡單。
除了request 上下文,還可以在其它數據綁定上下文中求值表達式,這些上下文用來訪問Web應用和頁面流環境的不同部分。綁定上下文還可以引用其它資源,比如通過url 或 bundle 上下文,它可以分別引用URL參數或資源包中的國際化字符串。完整的上下文及其引用對象/資源的列表如下:
上下文名稱 | 上下文引用的對象 |
actionForm | 和當前NetUI 表單標籤相關的動作表單 |
pageFlow | 某個用戶的當前頁面流 |
globalApp | webapp中某個用戶的Global.app |
bundle | 用於引用聲明或隱含的資源包屬性 |
pageContext | JSP 頁面的PageContext屬性映射 |
request | request的屬性映射 |
session | session的屬性映射 |
application | servlet上下文的屬性映射 |
url | 用於當前請求的URL 查詢參數 |
container | 當使用重複標籤繪製某個數據集時,複雜數據綁定標籤用它來訪問當前條目 |
現在進一步討論上表中提到的一些上下文。
同樣是使用表達式,仍然存在多種不同方法來引用同一對象的同一屬性。例如,在我們的例子中,以下幾個表達式都是等價的:
- request["customer"]["name"] - request.customer.name - request["customer"].name - request.customer["name"] [binding/index.jsp] |
而且,表達式既可以訪問字段,也可以訪問屬性,這些屬性返回任意基本類型或Java Object類型,也可以返回它們的數組、列表和映射類型。一般說來,屬性命名遵循JavaBean屬性的setter和getter方法命名規範。關於暴露、命名、引用數據綁定對象屬性的特殊規則將在下面進行討論。
注意:對象的值既可以是隻讀的也可以是可讀/寫的;對象對應的值的暴露方式決定了它對於表達式僅是隻讀的,還是當Web瀏覽器向服務器提交數據時該值是可更新的。
訪問屬性
爲了識別類暴露的可綁定數據屬性,表達式語言採用了JavaBean命名規範。符合以下條件的方法可以暴露一個只讀屬性:
- public 訪問權限 - 返回非void類型 - 無參數 - 以"get"作爲名稱的開頭 |
可以使用表達式來引用數據綁定上下文中符合以上條件的任意方法。JavaBean屬性的名稱被包含在表達式中。例如,類中定義了一個屬性:
public String getName(); [binding/index.jsp] [binding/Controller.jpf] |
在表達式中它被引用爲:
{request.customer.name} [binding/index.jsp] [binding/index.jsp] |
前提是一個Customer 對象被指定爲“customer”並可以從request中得到。
在本例中,方法 getName 對應名爲name的JavaBean屬性;這是通過去掉“get”並將第一個字符變成小寫之後得到的。一個例外是如果“get”之後的頭兩個字符都是大寫的,JavaBean屬性的名稱將在表達式中保持不變。例如,屬性:
public String getURL(); [binding/index.jsp] [binding/Controller.jpf] |
在表達式中被引用爲:
{request.customer.URL} [binding/index.jsp] [binding/index.jsp] |
迄今爲止,以上的name 和URL 屬性都是隻讀的,因爲我們沒有爲它們定義setter方法,該方法可以用來更新對象的屬性值。一個JavaBean的setter方法需要符合以下條件:
- 以"set"作爲名稱開頭 - 返回void類型 - 只有一個參數,它的類型與對應getter方法的返回類型相同 |
前面兩個屬性的JavaBean setter如下:
public void setName(String name); public void setURL(String url); [binding/index.jsp] [binding/Controller.jpf] |
如果對象中同時存在正確定義的getter 和setter,屬性就是可讀/寫的。這種類型的屬性十分重要,因爲可以從Web頁面更新它們的值。
訪問字段
可以通過表達式訪問公共字段。上面Customer類中定義的“eMail”字段就是一個例子。公共字段總是可讀/寫的。Customer的email地址在Web頁中可以顯示爲:
<netui:label value="{request.customer.eMail}"/> [binding/index.jsp] [binding/Controller.jpf] |
訪問數組或列表中的元素
使用常用的[index] 語法可以引用數組或列表中的條目。如果一個屬性被暴露爲:
public String[] getZipArray(); [binding/Controller.jpf] [binding/index.jsp] |
那麼可以通過以下表達式訪問數組的第四個條目:
{request.locationInfo.zipArray[3]} |
假定LocationInfo對象可以在request中通過關鍵字“locationInfo”進行訪問,
如果一個屬性被暴露爲:
public List getZipList(); |
那麼以下表達式將會訪問列表中的第四個條目:
{request.locationInfo.zipList[3]} |
此類表達式求值還是略有不同。如果該表達式在一個長度僅爲2的String[]上被求值,因爲數組的長度小於表達式的引用長度,所以將會發生錯誤。如果屬性是列表類型,表達式將被簡單地求值爲null。
使用NetUI Repeater標籤集可以方便地繪製數組和列表。稍候一篇dev2dev文章將會涉及該標籤集以及“container”綁定上下文。
訪問映射中的元素
表達式還可以採用與訪問屬性相同的語法來引用映射中特定鍵值對應的條目。例如,如果LocationInfo 類暴露了一個含有州名縮寫和州名的Map,並將其定義爲帶有JavaBean getter方法的可綁定數據屬性:
public Map getAbbrevMap(); |
那麼,以下兩個表達式都可以使用鍵值“CO”在映射中進行查找:
{request.locationInfo.abbrevMap.CO} |
訪問基本類型
採用以上任何機制暴露的數據類型可以是Java對象或基本類型。如果某個屬性或字段的類型是基本類型,比如int 或 boolean ,表達式的求值結果將是基本類型的Java對象包裝器。在本例中,將分別是Integer 和 Boolean。
表達式和NetUI JSP標籤
在NetUI JSP標籤上使用表達式、屬性可以引用業務對象屬性,並將數據顯示在Web頁面上。同一屬性的顯示方式取決於標籤的選擇。比如,綁定到NetUI label的字符串屬性是隻讀的,而綁定到NetUI form內NetUI text box的字符串屬性卻是可讀/寫的。
目前存在三個NetUI標籤庫——HTML、複雜數據綁定、模板,本文不涉及後面兩個。HTML標籤集儘可能遵循HTML4.01規範並將自己的標籤和HTML中定義的元素相互結合。例如,textBox、 checkBox、 和radioButton 標籤分別顯示HTML輸入標籤類型“text”、 “checkbox”、 和“radio”。可以在Workshop標籤面板中找到這些標籤。
也可以在Workshop 8.1的Insert菜單中找到這些標籤。
NetUI HTML 標籤進一步可以分爲兩類——只能顯示數據的標籤(或稱爲只讀的)、能夠在服務器和Web瀏覽器之間“往返”的標籤(或稱爲可讀/寫的)。可以使用諸如netui:form 內的textBox這類標籤在服務器和客戶端之間傳遞數據。關於此類標籤如何綁定數據,彼此之間也存在不同。
只讀NetUI標籤
只讀標籤使用表達式綁定屬性“value”來指定在頁面中繪製的數據。此類標籤只是簡單地通過表達式從業務對象中讀取數值並在Web頁面上繪製,可能還會對輸出結果進行格式處理。我們已經知道netui:label 標籤可以在頁面上繪製表達式的值,其實它也可以繪製普通文本:
<netui:label value="Blue"/> |
因爲label標籤不是到服務器的可往返標籤,所以它的value屬性可以是文本和表達式的組合。例如,想要顯示用反斜槓分開的客戶姓名和年齡,可以這樣使用label:
<netui:label value="{request.customer.age} / {request.customer.age}"/> |
每個表達式都將被求值,文本“/”將會混合到表達式結果中。
可讀/寫NetUI標籤
第二組標籤使用“dataSource”屬性,它們比較特殊因爲被“dataSource”屬性引用的數據可以在Web瀏覽器和服務器之間往返。儘管dataSource屬性可以綁定表達式,但該屬性的value必須是一個純粹的表達式。與label標籤的value屬性不同,dataSource屬性不能混合文本和表達式,因爲dataSource屬性的value被用在兩個地方:
- 繪製JSP頁面的時候通過表達式讀取值 |
採取這種方式,諸如textBox這樣的標籤就可以在服務器和Web瀏覽器之間來回傳輸數據。
如果在dataSource 屬性中混合使用文本,屬性就不是一個純粹的表達式並將報錯。因爲dataSource 屬性通常被用於同數據庫交換數據,所以這裏使用的表達式必須引用那些可以更新的數據綁定上下文,它們是actionForm、pageFlow、和 globalApp。 除此以外,所有其它綁定上下文在數據被POST到服務器時都是隻讀的。
一個簡單例子
讓我們對前面的Customer例子稍作修改並利用NetUI編寫一個“Hello World”,從而形成一個實用的例子。本例中含有一個頁面流simpleForm 和一個JSP。JSP定義了一個綁定到頁面流中某個action的NetUI表單。當表單從瀏覽器中POST的時候,動作表單將被創建,提交的數據將被添加到動作表單中。接着,輸入頁面被刷新,剛剛在只讀label中顯示的信息將會顯示到可編輯的文本框中。這裏所說的頁面流是指本文示例應用中的simpleForm。
首先我們來看看動作表單,它們負責封裝那些在頁面中被顯示並更新的數據。該類定義了通過NetUI HTML在JSP表單標籤內可編輯的屬性;它暴露了唯一一個屬性——message。
public static class MessageForm extends FormData |
接着我們來看看JSP頁面。這裏的netui:form 標籤用於引用在表單POST時將會執行的頁面流動作。如果您對頁面流不熟悉,請參閱參考材料部分的頁面流參考手冊。一般來說,從可讀/寫NetUI標籤POST到服務器的更新必須在NetUI form 標籤中進行。
<netui:form action="echoMessage" focus=""> |
JSP中有兩個附加NetUI標籤;其中netui:textBox 利用表達式{actionForm.message}在當前動作表單中顯示message的值。最初該值以及textBox都是空的。還有一個button標籤用來把表單提交到服務器。運行例子的時候,請在文本框中輸入“Hello World”並按下“Submit”。
看!當表單提交到服務器時,頁面流生命週期創建了接收POST數據(即本例中的message)的動作表單。因爲textBox的dataSource 屬性對應的表達式被映射爲HTML輸入標籤——{actionForm.message},所以message的值被路由到該屬性上。
一旦表單填充完畢,postback 動作就會執行並在頁面中重新繪製相同的表單。運行結果是:表達式{actionForm.message} 現在同時指向label和textBox 中顯示的“Hello World”。在文本框中輸入文本並重新提交表單可以修改該值。
技巧和經驗
如何訪問頁面流的成員屬性?
頁面流可以像其它類一樣暴露JavaBean屬性;利用表達式和pageFlow 綁定上下文可以綁定這些屬性。例如,如果一個頁面流用以下方法暴露屬性productName:
public String getProductName() |
就可以通過以下表達式在JSP中進行數據綁定:
{pageFlow.productName} |
你還可以綁定到頁面流暴露的公共字段。
應該在頁面流上暴露映射嗎?
在任何可以接受POST數據的數據綁定上下文中暴露Map類型都是危險的。問題在於映射可以變得很大,這就在服務上開了一個安全漏洞:因爲網頁可以直接POST數據到Map,這將會導致map無限變大、消耗掉可觀的服務器資源。
通過類似request這樣的只讀數據綁定上下文來暴露Map類型要安全很多。上面的例子中,LocationInfo對象通過abbrevMap 屬性實現了這點。
如果在表單上暴露一個int 類型的屬性,從頁面POST出去的是什麼類型?
當JSP頁面POST數據到服務器時,所有的數據都以字符串形式到達。應用POST數據到頁面流屬性或動作表單的過程中,NetUI會設法把已經POST到底層屬性或字段的字符串數據轉換爲原有的類型。
例如,如果動作表單暴露一個類型爲int、名稱爲 age 的屬性,並且該字段可以從NetUI表單更新,類型轉換工作即是把String 類型的“42”的轉換成int 類型的42。如果轉換失敗,失敗信息將會顯示在運行WebLogic的命令提示窗口中。
如何顯示一個數據列表或數組?
利用NetUI複雜數據綁定標籤可以繪製諸如列表、數組、映射、和行集這類的數據集。這些將在接下來的dev2dev文章中討論。
表達式求值失敗會怎樣?
當JSP準備繪製時,如果一個表達式求值失敗了,JSP頁面上將會顯示一個失敗信息。假定有屬性綁定的例子:
Customer Name: <netui:label value="{request.customer.name}"/> |
如果request的屬性映射中不包含名爲“customer”的對象,那麼綁定將會失敗,因爲name屬性無法訪問null對象。請嘗試將例子改爲:
Customer Name: |
這樣就可以知道表達式求值是如何失敗的了。
Workshop 8.1 IDE如何幫我進行數據綁定?
Workshop可以用多種方式幫助JSP作者進行數據綁定,其中最重要的一種是通過數據面板。使用數據面板可以在JSP頁面中創建能夠顯示或更新數據的NetUI標籤。
例如,在Workshop中打開JSP頁面howdoi/index.jsp;在頁面上,數據面板顯示如下:
您可以看見productName屬性在面板中是可用的。如果拖動它到JSP頁面中,以下代碼將被生成並將在頁面中顯示產品名稱:
<netui:label value="{pageFlow.productName}"></netui:label> |
試着添加其它屬性到頁面流中並拖動它們到JSP頁面中,從而生成可以顯示數據的NetUI標籤。
如果頁面上有動作表單,它上面的屬性也可以被拖動到JSP上。
結論
本文覆蓋的範圍很廣。現在重新回顧一下,表達式語言使得NetUI JSP能夠引用業務對象暴露的數據、頁面流、以及數據綁定上下文暴露的其它對象和資源。表達式可以引用這些對象的屬性和字段,並且NetUI HTML標籤既可以用於顯示數據,也可以用於從Web瀏覽器更新數據。
本文附帶的應用程序包含多個示例,其中包括基本數據綁定規則的例子、Hello World例子、和一個創建、顯示、和編輯Customer對象的複雜例子。
在以後的文章中我們還會介紹更多的內容,希望本文使您對WebLogic Workshop 8.1的從UI到數據的綁定有了初步瞭解。
作者簡介 | |
Eddie O'Neil是Apache Beehive VP / PMC的主席,也是BEA公司的專職工程師。目前他專門負責Beehive,此前他曾致力於WebLogic Workshop 8.1和WebLogic Portal。他持有維吉尼亞大學的計算機科學學士和碩士學位。 |