2009年4月8日 星期三

[Struts2] Introduce OGNL

Object-Graph Navigation Language(OGNL) 是 Struts2 framework 中很重要的一個 component 之一,OGNL 負責作 data transfer 與 type conversion 的工作,並且讓 programmers 可以很簡單的將網頁上的 String-based data 轉換成 Java type-based data。其實,我們在之前就已經使用過 OGNL 將資料由 ValueStack 中搬進跟搬出,而且使用的方式很簡單!
OGNL 並不是 Struts2 framework 中所特別發明的,而是被 Struts2 framework 所整合的一種技術,從 programmer 角度來看,OGNL 包含了兩種功能:1) expression language 與 2) type converter。

Expression Language
如果你有用過 JSP 中標準的 EL 的話,這裡的 expression language 你應該就會有點感覺,因為 OGNL 的撰寫方式跟 JSP 中的 EL 是很類似的!OGNL 的 expression language 一種連結 HTTP 端的 string-based data 與 Server 端 Javabean 的 Java type-based data,並且可以將這兩端的 data 作相互的轉換。讓我們回顧一個小小的範例:
<s:property value="user.age" />

這個 property tag 是之前我們就使用過的,我們的 OGNL 就是寫在 value attribute 中的 String,這個 OGNL 就是將目前 Action 中的 user property 取出,再進一步的取出 user 中的 age property,所以 user property 是另一個 Javabean。這個 OGNL 很簡單,但是 OGNL 也可以撰寫得很複雜,OGNL 本身有提供很多好用的 built-in 讓 programmers 可以很容易的存取 ValueStack 中的值!
這裡你可能會有一個問題:Struts2 framework 怎樣知道哪個 String 是屬於 OGNL 哪個 String 是真正的字串呢?其實這就是 Struts2 tag 本身的設定了,有些 tag 的某些 attributes 可以寫 OGNL,而有些只能是純字串,而 OGNL 為了讓 programmer 在純字串的 attribute 中可以撰寫,我們可以採用 %{ expression } 的方式,這樣就保證一定是 OGNL!所以我們也可以將上面的 OGNL 撰寫成這樣:
<s:property value="%{user.age}" />

不過要知道哪個 tag 的哪些 attributes 是可以 parse 或不能 parse OGNL 語法,我們就要參考 Struts2 framework 官方文件的 Tag reference,這份文件包含了所有的 Struts2 tags,我們在這裡不會詳談,不過你可以點進去各個 tag 看看該 attribute 的 type,例如:property tag 的 value attribute 屬於 Object,這就代表 value attribute 可以 parse OGNL 語法!

Type Converter
OGNL 不僅僅是一種 expression language,他還會幫我們將資料型態進行轉換,也就是扮演著 type converter 的角色。其實在上面的範例中我們就示範了 OGNL 的 type conversion。因為在 user class 中的 age property 是屬於 int 型態,我們透過 OGNL 存取 Action 中的這個值,OGNL 就會幫助我們將 int 型態的 property 轉換成 string-based data,因為在 HTTP 之下,所有的資料都會是字串而已,但是在 server 端的 Javabean 中卻可以有很多種型態的資料!所以,OGNL 將資料由 Javabean 搬移到網頁上或是由網頁上搬移到 Javabean 中都會進行 type conversion。這樣的功能無須 programmer 的插手,OGNL 會自動的偵測 data 要轉換的型態!
在 Struts2 framework 中有針對 OGNL 的 type conversion 機制提供了很多種內建的 converter,當然,Struts2 framework 也有讓 programmer 可以自行定義 convert er 的功能!不過那是之後我們才會在提到了!

由上面的敘述中我們瞭解了 OGNL 在 Struts2 framework 中所扮演的角色後,我們就要來描述一開始提到 OGNL 的另咦項中要的工作:Data transfer。也就是 OGNL 如何與 Struts2 framework 之間進行互動。讓我們先看看下圖:
寄件者 阿信 (Silver8250) 的冷泡咖啡館~

這張圖顯示了整個 data 如何在 OGNL 之下由 client 端到 server 端的進出!這裡所謂的 client 端就是圖中最下方的兩個 HTML 檔案,因為這最終還是使用者看到的格式。以下我們將這圖中的兩個部份分開介紹:1) Data in 與 2) Data out。

Data In
一開始使用者會先看到 index.html,當然,這個檔案是我們的 JSP 檔案,不過透過使用者的瀏覽器看到則是一些純粹的 HTML。然後使用者透過瀏覽器輸入資料後,就會將資料轉交給 Servlet,透過 HTTP 方式以 key value pair 方式傳送,就如圖中的 Servlet Request 的內容,Servlet Request 會將這些 key value pairs 轉交給 OGNL Expression Language and Type Converter 作處理,接下來就是 OGNL 的工作了!
首先,OGNL 會知道資料要去 ValueStack 中存取,並且 OGNL 會自動的知道要存取在 ValueStack 中的哪個 Action 物件,如同圖中的 HelloUser 這個 Action 物件。接下來就是 param interceptor 的工作了,我們在內建的 Interceptors 中提到 param interceptor,他會根據 OGNL expression 將資料與 ValueStack 中的 Action 物件作 mapping,並且找出該 data 最終要存放的位置。例如 param interceptor 會將圖中的 user.age 對應到 HelloUser 中 User 物件的 age property。
一旦 param interceptor 決定好該 data 的最後歸宿,OGNL 就會負責呼叫該 property 的 setter method,不過我們原始的資料是 string-based data,在 User 的 age property 確定 int 型態,這時候就會用到 OGNL 的 Type Converter,OGNL 會先使用內建的 converter 來試圖轉換型態,如果沒有才會用使用者自訂的 converter 來轉換,如果都沒有辦法轉換,則會拋出 Exception。最後 string-based 的 "24" 會被轉換成 Java type 的 int 型態的 24,並且儲存到 ValueStack 中。
在這裡我們不用知道太多關於 ValueStack 的內容,我們現在只要知道 ValueStack 就是一個 Stack 的容器,他會負責儲存所有的 Action 物件等等。如果有兩個物件都有 age property,則只會有一個 property 會被存取!

Data Out
至於另一半的作業其實也是很類似,只是方向相反罷了!當 Struts2 framework 接收到使用者的 request 後會執行我們之前所談到的 interceptor stack,並且執行 Action 中定義的 business logic,當產生了使用的 Result 頁面後,OGNL 就會開始啟動作業了!就如同圖中的 Welcome.jsp 頁面,裡面宣告了 OGNL expression:user.age,OGNL 就會根據 expression 到 ValueStack 中取得確實的值,並且將這些值轉型成 String 型態。最後就會變成使用者瀏覽器看到的 Welcome.html 的內容。

在這裡我們瞭解到 OGNL 在 Struts2 framework 中的主要工作以及其扮演的角色,並且瞭解到 OGNL 如何與 Struts2 framework 中的 component 互動的資訊。

沒有留言: