2009年4月21日 星期二

[Struts2] 建立自訂的 OGNL Type Converter

Struts2 framework 中的 OGNL Type Converter 已經滿足了我們大部分的情況,基本上我們可以不用自己建立自訂的 Type Converter,不過 Struts2 framework 還是提供了讓我們可以自訂 Type Converter 的機制!在這裡我將示範要如何建立一個自訂的 OGNL Type Converter!範例中主要是提供一個 UserTypeConverter:將頁面上的 User data 轉換成 Action 中的 User property。

Implement a type converter
Struts2 framework 中,所有的 OGNL Type Converter 都必須 implements TypeConverter interface,這個 interface 提供了 programmers 在任何兩種類型的 data 進行轉換,不過在 Web application 中,我們只需要在 String 與 Object 之間作轉換就可以了!所以,我們自訂的 Type Converter 就採用 Struts2 framework 定義的 StrutsTypeConverter。StrutsTypeConverter 是一個 Abstract class,我們的 Type Converter extends StrutsTypeConverter 之外,還需要實做出兩個 abstract methods:
public abstract Object convertFromString(Map context,
                      String[] values, Class toClass)
public abstract String convertToString(Map context, Object o)
這兩個 methods 從 method name 就可以很清楚的瞭解其目的,convertFromString 主要是將頁面上 String-based data 轉換成 Java type property;而 convertToString 就是將 Java type property 轉換成 String-based data。

Convert between Strings and User
接下來就整個重頭戲了!我們要實際的撰寫我們的 Type Converter:
public class UserTypeConverter extends StrutsTypeConverter
{
  @Override
  public Object convertFromString(Map context, String[] values, Class toClass)
  {
     String name = values[0];
     String password = values[1];
     User user = new User();
     user.setName(name);
     user.setPassword(password);
     return user;
  }
  @Override
  public String convertToString(Map context, Object o)
  {
     User user = (User) o;
     return "User:name="+user.getName()+", password="+user.getPassword();
  }
}

首先,就如我們之前提到的,我們的 Type Converter 要 extends StrutsTypeConverter class,然後實做出兩個 abstract methods。將字串轉換成物件的 method 中,我們主要是將使用者在頁面上輸入兩個字串,而這兩個字串會分別變成 User 物件中的 name 與 password!在這裡沒有什麼邏輯可言,因為我們只是要示範 Type Converter 罷了!反之,將物件轉換成字串時,我們就是將 User 物件顯示成一個字串,這就有點像是 toString() method 一樣,純粹將物件中的資訊轉換成字串!

Configure our type converter
撰寫完我們自訂的 Type Converter 之後,那我們要如何讓 Struts2 framework 知道呢?我們需要一個設定檔!在 Struts2 framework 中提供了兩種方式讓我們可以設定我們的 Type Converter :1) Property-specific 與 2) Global type converter。

1. Property-specific
這種方式的設定檔只能針對某個 Action 的某個 property 給予我們的 Type Converter!首先,我們要先建立一個設定檔,檔案的命名規則為:{ActionName}-conversion.properties。假設我們有一個 Action 為 UserTypeAction,此 Action 中當然要有 User property,然後我們就必須建立一個設定檔名為:UserTypeAction-conversion.properties,而這個 properties 檔案要跟 UserTypeAction 在同一個資料夾中!在設定檔中我們要撰寫如下:
user=silver8250.type_converter.UserTypeConverter

其中,先告知 Struts2 framework 我們要進行轉換的 property 為 user,然後在等號右邊給予我們的 Type Converter!這樣就完成了設定檔案!
這種設定檔到底有什麼好處呢?一開始你應該會很困惑,因為我們不可能為每一個 Action 中有使用 User property 都增加一個設定檔,我們一定是會使用等等會談到的 Global 設定檔!不過在某一種情況下會有用處!假設我們有兩個 Type Converters,第一個是 Global 的,所以我們採用 Global 的設定讓大多數的 property 都使用,不過如我們有某個 Action 的某個 property 要使用我們設計的第二個 Type Converter,這時候 property-specific 就派上用場了!因為 Struts2 framework 會先以 property-specific 設定優先!

2. Global type converter
另一種設定檔就是 Global 型態的 Type Converter,我們只需要一個設定檔為:xwork-conversion.properties 檔案,並且放在 WEB-INF/classes 之下就可以!內容如下:
silver8250.bean.User=silver8250.type_converter.UserTypeConverter

等號左邊是告訴 Struts2 framework 是哪一個 Object 要執行 Type Conversion,右邊則是要使用哪個 Type Converter 進行轉換!這樣就完成了 Global 的設定檔!大多數的情況下我們都是以 Global 設定檔為主!

Use our type converter
最後就是我們在頁面上要如何撰寫呢?其實沒有任何的差別!例如:我們的 Type Converter 是要讓頁面上的兩個字串轉換到 User 中的 name 與 password,所以我們在頁面上就要設計兩個 textfield 讓使用者輸入:
<s:form action="UserType" method="GET">
   <s:textfield name="user.name" label="User Name"></s:textfield>
   <s:textfield name="user.password" label="User Password"></s:textfield>
   <s:submit></s:submit>
</s:form>

你沒看錯!真的沒有差別!真的~

在這裡我們示範了要怎樣設計自己的 Type Converter,不過大多倏地行況下,我們不需要這樣作!

1 則留言:

Unknown 提到...

阿信大: 我剛好有要用到這個轉換, 感謝您的詮釋, 不過此例最後設計的兩個 textfield 是不是筆誤? 兩個name都只打了 name="user" ??? 應該是和另一例一樣打 name="user.name" , name="user.password" 才對呢?? 我是看到迷糊了 =.= (又不敢用力推翻,哈哈)