顯示具有 struts 標籤的文章。 顯示所有文章
顯示具有 struts 標籤的文章。 顯示所有文章

星期二, 7月 17, 2007

struts 2: field validation and type conversion

一般web 應用中,很基本的一個功能是參數的驗證(validation),而在struts 2中,這個功能是透過validation來達成的。但是,在驗證之前,struts 2會先做type conversion 的動作,以確定輸入的參數能夠滿足action 中各個properties的需求。所以,interceptor的執行順序是
  1. 型別轉換 (type conversion)
  2. 參數驗證 (validation)
如果在型別轉換時就發生錯誤的話,相同的欄位就不會進行參數驗證。我就是忽略了這個順序,才搞了二天。

舉例來說,如果有個property 是 setDate(Date theDate),在zh_TW的locale中,預設的日期格式是mm/dd/yyyy,我想在為這個欄位加上validation, 於是,在我的Action-validation.xml中有下列的一段程式碼:


<field name="date">
<field-validator type="regex">
<param name="expression"> ...</param>
<message>wrong format for field date</message>
</field-validator>
</field>


但是,當格式錯誤時,regex卻不會抓到錯誤,問題就是出在type conversion 的interceptor 先運作了,所以總是會出現type conversion 的錯誤訊息 : "Invalid field value for field "date"",所以,對於非String 型態的property,比較有意義的validator只剩下required、date、int這幾個有意義,其他的意義都不大。

那接下來的問題就在於,怎麼把"Invalid field value for vield ..." 這段訊息換成我們想顯示的訊息。這必需透過struts 2的I18N機制來達成,根據AnnotationXWorkConverter文件中提到的,可以在ClassName.properties中設定 invalid.fieldvalue.欄位名稱,來設定特定欄位的conversion error錯誤訊息,如果要改變預設的訊息的話,則可以透過設定global的I18N屬性xwork.default.invalid.fieldvalue 來達成效果。

星期一, 7月 16, 2007

sturts 2 validation and action property

今天又犯了個豬頭錯誤,我有兩個Struts Action,程式碼類似這樣:
public class ParentAction {
protected long property;
...
public long getProperty(){
return property;
}
}

public class ChildAction extends ParentAction{
public void setProperty(int property ){
this.property = property;
}
}

當我對ChildAction 加上required validation時,問題就來了,不論我輸入的是什麼值,validation interceptor總是告訴會回報property is null,找了半天,一路trace到Ognl層,才發現問題出在,透過reflection API取得property 的method descriptor時,因為setProperty的參數型態和getProperty的參數型態不符,而getProperty又在parent,所以會只認getProperty,而把setProperty(int) 當作是一個overloading method,以致於無法設值進去,只要把setProperty 由setProperty(int)改成setProperty(long),就又能夠正常運作了。

這樣的錯誤,只能說是自己不小心造成的,但是,這種錯,應該會常常發生吧,下次,得把這類的檢查也加到test case中。

星期五, 6月 01, 2007

在Struts2 中取得JAAS相關資訊

在WebWork/Struts 2的應用框架中,可以讓系統開發者在寫程式時,專注在應用系統的邏輯,透過IoC的注入(injection)方式,程式碼中可以完全看不到與JavaEE相關的程式碼。但是這種美好的世界,在遇到一些需要根據使用者傳回不同的結果的action時,就不是那麼美好,除非你所開發的應用系統自行處理使用者權限與授權相關的功能。如果是使用JAAS,那程式中不免會需要透過HttpRequest來取得remoteUser等資訊。在Struts2/WebWork中,提供了兩個介面可以做到這樣的功能 HttpRequestAwarePrincipalAware。


HttpRequestAware 是第一個會想到的介面,既然remoteUser的資料是從request來的,那就叫struts幫我們注入個request object不就成了?但是一但在action中引入HttpRequest,使用Struts2/Webwork的最大好處,與平台低相依性,易測試的優點就當場被破壞了。當引入HttpRequest之後,為了測試action,必需透過如spring-mock等等的JavaEE mock 套件,無法簡單的透過如jmock, 或是自行打造stub的方式來進行測試,而且,只是需要getRemoteUser, isUserInRole等function,卻把整個HttpRequest 都暴露在action中,怎麼看味道也不對。


PrincipalAware 就是為了解決上述的問題產生的,如果你只是很單存的需要getRemoteUser, isSecured, getPrincipal, isUserInRole等功能,那action只需要實作PrincipalAware,Struts2/WebWork會為action注入一個PrincipalProxy,提供getRemoteUser等需要的方法,又不需要將整個HttpRequest都暴露在action中,造成與平台過度的相依。更好的是,PrincipalProxy是一個interface,可以利用jmock, dynaMock等mock framework簡單的產生測試時需要的替代品,對自動測試可是一大利多。


使用WebWork到現在,也好幾年了,居然到現在才發現有這個interface,該說是後知後覺,還是太不認真了,不過,這個介面可是解決了以往為了測試這些需要principal 的action,而搞了幾乎整套的JavaEE stack的問題,又能夠滿足整個應用系統的味道能夠一致,真該認真點的。

星期一, 2月 26, 2007

struts test with remote user

最近遇到一個閃不掉的struts系統開發,慘的是,只能用struts 1.x這個我一直很努力避免使用的framework。不過,既然遇到了,還是得用,利用StrutsTestCase來作單元測試(unit test),一開始倒也還相安無事,一直到遇到一些需要用到HttpRequest.getRemoteUser的action,一時之間,還真不知道該從何著手,只有個概念該從mock object的方向做。
不過,幸運的讓我找到一篇Testing Struts的文章,其中提到了利用MockStrutsTestCase來作security的unit test,再追了一下StrutsTestCase的原始碼,果然,在MockStrutsTestCased中使用的HttpServletRequestSimulator 這個mock object可以由程式碼給定RemoteUser等request的相關資料,總算解決了我的問題。
Struts 1.x算是個很成熟的framework,相關的討論,隨便找找也都是2004年,甚至更早的文件,很多文件,還真的跟不太上目前的狀況,還好這篇的東西還可以用,不然,就真的很麻煩了。