2009年2月15日 星期日

[Struts2] 深入實做 Action

初啼試聲 HelloStruts2 中我們已經簡單的實作出一個 HelloUser 的 Action。Struts2 中的 Action 可以簡單到只是一個 POJO,但是我們也可以將我們的 Action 藉由 implement 或 extends 一些 Struts2 內建的 interfaces 或 class 撰寫出更方便、更具有 powerful 的 Actions。最基本的 Action 就是不必與任何的 interfaces 或 class 有牽連,不過,以下將會介紹一個 interface 與一個 class,讓 programmer 在撰寫 Action 時可以更方便!

Implements Action interface

Action interface 是 Struts2 中內建的,讓 programmer 強制去撰寫出 execute() method,畢竟 Action 是一定要有 execute() method 的!不過這個 interface 不只是這樣,還提供了五個內建的控制字串,我們可以藉由回傳這些內建的控制字串,讓 Struts2 可以幫我們作智慧型的預設控制!不過,我們在設定檔中的 <result> 還是要有對應的 name 才行喔!假設我們的 Action 中 execute() method 如下:



public String execute()
{
return INPUT;
}

那我們就要在設定檔中有對應的 result tag 的 name="input" 才會有作用!



<result name="input">/index.jsp</result>

Note:Struts2 的 Action 不一定要實做 Action interface,實做 Action interface 卻可以提醒粗心的 programmer 去撰寫 execute() method!

另外,如果我們只是要負責將網址作轉換的 Action,例如我們不希望在網站中直接利用頁面的 URL 作為連結,想要透過 Action 來對應到一個頁面,我們可以不必費心的撰寫出一個空的 Action,我們只要在設定檔中加入一個 <action> tag,並且對應到一個沒有 name 的 <reuslt> tag 就可以囉!



<action name="IndexPage">
<result>/index.jsp</result>
</action>

上面的設定是利用一個空的 Action 名稱為 IndexPage 來對應到我們的 index.jsp 頁面。所以我們在網站中要對應一個 index.jsp 的連結,我們可以不必用絕對的 URL,反而可以使用 IndexPage.action 來對應,這樣的好處是當我們在變更 index.jsp 的 URL 時(假設首頁要改到別頁去),我們可以不用大費周章的修改每一個有撰寫 <a href="index.jsp"> 的頁面,反而因為我們是撰寫 <a href="/IndexPage.action"> 使得我們只要改設定檔的對應就好了!

Extends ActionSupport class

另一個很方便的 class 是 ActionSupport class,這個 class 提供了更多的功能,也幫一般在撰寫 Action 的 programmer 自動的 implements 我們可能會用到的 interfaces,如:上面所提到的 Action interface、用於驗證的 Validateable interfaceValidationAware interface 等等。並且幫我們實做出這些 interfaces 的 abstract method,所以說 ActionSuppert class 可以算是一種 Default Adapter pattern。

對於初學 Struts2 的 programmer 來說,ActionSupprt class 可以說是很方便也很常用的 class,不過,既然是繼承的關係,當然就會帶有一些缺點囉~不過我們也不是一定要繼承 ActionSupport 啦~

以下將分兩個部份介紹 ActionSupport class 所提供的功能。

1. Basic validation

剛才有說過 ActionSupport class 有實做出 Validateable 與 ValidationAware interfaces,所以 ActionSupport class 也會有幫我們實做出預設的 validate() method,不過內容當然是空的!也就是說,我們可以透過 override validate() method 來撰寫我們自己的驗證程式。



public void validate()
{
if (GenericValidator.isBlankOrNull(this.name))
{
super.addFieldError("name", "Name is required!");
}
}

上面的驗證程式是針對我們的 HelloUser 所撰寫的!用來驗證使用者在我們的 index.jsp 頁面中是否有輸入非空白的字串,所以我們採用 Commons 的 Validator framework,很幸運的 Struts2 的 Validation framework 就是採用 Commons 的!所以我們無須在下載多餘的 library 就可以使用了!另外,我們在驗證出現不合法的情況下呼叫 ValidationAware interface 的 addFieldError() method (),根據 addFieldError() method 的 parameter 說明就可以知道,第一個 parameter 是要告知 Struts2 哪一個欄位有錯誤,這樣當回到原先輸入的頁面時,Struts2 會自動在該欄位附近顯示我們的第二個 parameter 訊息給使用者!

有一點要特別的注意,因為我們使用了 validate() method 來驗證使用者輸入的值,所以我們在設定檔案中一定要有 <result name="input"> 的設定,不然當我們的驗證程式找到錯誤就回不到原來的頁面了!

P.S. GenericValidator 提供了很多很好用也很常用的驗證程式,例如我們所使用的 isBlankOrNull 就是驗證是否為空白或是 null!

說了這麼多關於驗證的東西,那這個 validate() method 到底是誰在驅動呢?回想一下我們在 How Struts2 works 中有提到 interceptor 這個東西吧~他會在我們 Action 被執行前就會先執行 interceptor stack,所以確實是有一個 workflow 的 interceptor 在幫我們呼叫 validate() method,不過我們在之後才會在深入的探討 interceptor。

2. Using ResourceBundles for message text

回到上面的程式碼中,如果你像上面的程式碼一樣直接將錯誤的訊息寫在程式碼裡的話,想必你一定會為日後的維護工作感到煩心~如果哪天主管要你加入英文版本、中文版本的訊息!你一定會因為這樣的苦差事感到心有餘而力不足阿!為了避免這樣的事情發生,Struts2 framework 有支援 I18N(Internationalization) 與 L10N(localization)的機制。很幸運的 ActionSupport class 有實做了兩個 interfaces 是負責這兩種機制的:TextProviderLocaleProvider interfaces。

TextProvider interface 是可以讓我們很有彈性的取得我們的訊息,也就是藉由設定在 ResourceBundle 中的 Key-value pattern 來取得,我們透過呼叫 TextProvider 的 getText() method 並給予一個 key 來得到 value。

如果我們將我們在 HelloUser class 中的 validate() method 更改為:



public void validate()
{
if (GenericValidator.isBlankOrNull(this.name))
{
super.addFieldError("name", super.getText("error.name"));
}
}

那我們就可以放置一個與 HelloUser class 同一個位置的 HelloUser.properties 檔案,如下圖中 HelloUser.properties 檔案放置的路徑就為 /silver8250/hello/。

並且設定我們要作 I18N 的訊息:



error.name=請輸入您的姓名

如果我們在 Eclipse 中編輯像上面 properties 檔案中的非英文文字,那我們就可以參考 Struts 解決中文問題 中提到的 PropertyEditor 這樣的 Eclipse plug-in。

LocaleProvider interface 則是提供了 getLocale() method 讓我們可以根據瀏覽器中的不同語系設定來轉換在頁面上所顯示的文字。

在此對於 I18N 與 L10N 並不會提到太深入,因為在之後我們對針對這樣的議題進行討論~

對於 Struts2 中的 Action,我們可以看到 Struts2 framework 中提供了兩種很方便的 interface 與 class 來幫助我們撰寫 Action,也提供預設的五種控制字串的功能,另外,我們探討了驗證的機制與多國語系的機制。

沒有留言: