前一段時(shí)間我寫過一篇
共享我在項(xiàng)目中使用jsf的一些經(jīng)驗(yàn),主要是概要的提出了一些jsf使用上的建議,這次我想在文章里主要是把seam在jsf中的使用經(jīng)驗(yàn)提一下,能讓更多的人了解seam的實(shí)際應(yīng)用和優(yōu)勢(shì)。
1.seam配置時(shí)要注意的地方:
(1)faces-config.xml里面要加入一個(gè)seam的階段監(jiān)聽:
<lifecycle>
<phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
<!-- <phase-listener>com.future.egov.jsf.ext.event.DebugPhaseListener</phase-listener> -->
</lifecycle>
seam動(dòng)起來(lái)的條件就是從這里發(fā)起的,seam通過這個(gè)監(jiān)聽器對(duì)jsf的各個(gè)階段進(jìn)行必要的增強(qiáng)以及植入自己的CONVERSATION生命周期,對(duì)于這個(gè)監(jiān)聽器的具體細(xì)節(jié)工作,我還需要更多時(shí)間研究,仍在了解中!
(2) 一定要在工程類路徑的根下放置一個(gè)seam.properties文件,你可以設(shè)置為空內(nèi)容,主要是引導(dǎo)seam在初始化的時(shí)候加載這個(gè)路徑下所有標(biāo)注為seam組件的對(duì)象(通過@Name注釋),
http://www.ibm.com/developerworks/cn/java/j-seam1/ seam無(wú)縫集成jsf給我了提示!
(3)web.xml下最小配置是加入seam監(jiān)聽器
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
在容器加載工程的時(shí)候,初始化seam框架。
以上三處的配置,你就可以在任何容器中使用seam了!更多的配置大家可以找參考了解吧,我目前在項(xiàng)目中就使用了以上配置。其他配置主要是在seam對(duì)ajax,ejb3的支持上,不過seam很新,什么事都會(huì)發(fā)生!
2.常用的注釋:(所有被seam定義的領(lǐng)域?qū)ο蠖伎梢哉J(rèn)為是seam組件)
(1)@Name(XXX),需要在你的領(lǐng)域類上定義,定義了seam組件的名稱,對(duì)于jsf來(lái)說(shuō)就是backing-bean,也就是說(shuō)你不用在faces-config中配置managedbean了!
(2)@Scope(ScopeType.XXX),可以在你的領(lǐng)域類上定義,表示這個(gè)被定義的seam組件在什么上下文中,jsf中主要包括page,event,session,application,conversation這些Scope。我在項(xiàng)目中主要使用event,session,conversation。event就是把組件放入了request中,session同理,conversation是seam獨(dú)創(chuàng)的聲命周期,conversation短聲命周期類似request,但是會(huì)保存一些jsf容易在請(qǐng)求中丟失的數(shù)據(jù)(jsf只是保存組件,不保存組件渲染的數(shù)據(jù),除非是EditableValueHolder組件,有時(shí)候需要通過myfaces的save組件和updateActionListener組件來(lái)恢復(fù)這些數(shù)據(jù)),具體保存細(xì)節(jié),需要看使用的情況,我有這樣一個(gè)經(jīng)驗(yàn):當(dāng)定義成event上下文,在頁(yè)面的一次請(qǐng)求中,有些數(shù)據(jù)請(qǐng)求時(shí)還在,但是到渲染時(shí)就不見了,常見在dataTable組件,myfaces的commandNavigation組件,但是換成conversation上下文,這些數(shù)據(jù)在渲染時(shí)又找回來(lái)了。但是對(duì)于跨度比較大層面,我還是推薦使用myfaces提供的保持機(jī)制,我一般使用updateActionListener,而save組件在seam1.2.1的環(huán)境下會(huì)出錯(cuò)。如果再有更大跨度,就可以使用conversation上下文的長(zhǎng)會(huì)話了。
(3)@Begin(join=true),@End(beforeRedirect=true),當(dāng)觸發(fā)了帶有@Begin標(biāo)記的方法,conversation的長(zhǎng)會(huì)話就這樣開始了,主要是為了長(zhǎng)時(shí)間使用已經(jīng)加載到conversation域中的對(duì)象或者屬性(如果定義了conversation但并沒有加載的可不算):join=true就是告訴你會(huì)話中有同名值時(shí)繼續(xù)賦值,還有一個(gè)注釋參數(shù)ifOutcome=XXX,就是看你的方法返回的字符串是否和ifOutcome定義的字符串相匹配,如果匹配就開始長(zhǎng)會(huì)話。當(dāng)在長(zhǎng)會(huì)話期間執(zhí)行到某個(gè)方法帶有@End標(biāo)記那么這個(gè)長(zhǎng)會(huì)話就會(huì)結(jié)束,這樣防止了內(nèi)存泄漏問題,我認(rèn)為這是一個(gè)權(quán)衡的結(jié)果,也許用戶真的會(huì)點(diǎn)擊那個(gè)帶有結(jié)束標(biāo)記方法的按鈕。beforeRedirect為真就會(huì)在結(jié)束時(shí)清掉conversation上下文所有的信息,如果beforeRedirect=false,conversation只是變成短會(huì)話,在結(jié)束后的那次請(qǐng)求中還可以使用conversation中的數(shù)據(jù),一般會(huì)用在messages提示這個(gè)應(yīng)用場(chǎng)景中使用,但是如果要返回?cái)?shù)據(jù)列表有時(shí)就需要清空所有數(shù)據(jù),防止數(shù)據(jù)列表還會(huì)重現(xiàn)長(zhǎng)會(huì)話開始前的情況。
(4)In(value=XXX,rquest=false,ScopeType=XXX),Out(value=XXX,rquest=false,ScopeType=XXX) seam把它定義為雙射。In是最常用的標(biāo)注,你可以使用In導(dǎo)入一個(gè)jsf的EL變量來(lái)獲取jsf模型,例如我要獲取spring的業(yè)務(wù)bean,而且業(yè)務(wù)bean已經(jīng)定義成backing bean,利用spring與jsf集成的方法:
<!-- Managed Beans for options.jsp -->
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
<locale-config>
<default-locale>gbk</default-locale>
</locale-config>
<message-bundle>resources/MessageBundle</message-bundle>
<!-- <view-handler>com.icesoft.faces.facelets.D2DFaceletViewHandler
</view-handler> -->
</application>
在seam組件中這樣聲明:
@In(value="#{userService}", request=false)
private UserService userService;
這個(gè)示例為seam組件注入了由spring管理的用戶服務(wù)對(duì)象,它的value是從jsf EL變量中獲取,request=false在告訴seam,如果當(dāng)前的值沒有找到,那么設(shè)置為空,否者當(dāng)出現(xiàn)沒有找到的情況,seam會(huì)拋出空異常。
@Out屬性主要是把處理過的屬性值會(huì)由seam重新再付給上下文也就是Out中所定義的ScopeType上下文,我認(rèn)為雖然是seam的一個(gè)特點(diǎn),但是在我的應(yīng)用中不多,主要是注入而非雙射!如果它真的能在短期Conversation中有所作用來(lái)代替Myfaces的數(shù)據(jù)保持機(jī)制,我想會(huì)好些,我目前只是在長(zhǎng)Conversation有所應(yīng)用。
3 .@Factory,@DataModelSelection,@DataModel,它們主要來(lái)代替數(shù)據(jù)列表的使用,主要是減少了代碼量,F(xiàn)actory是在請(qǐng)求值階段就對(duì)需要實(shí)例化的對(duì)象進(jìn)行創(chuàng)建,DataModelSelection定義的屬性,可以透明的抓取數(shù)據(jù)列表選擇的單行數(shù)據(jù),DataModel屬性減少了不必要的get,set。然而我在實(shí)際的使用中由于很多不定的情況,大部分的使用上又回到j(luò)sf標(biāo)準(zhǔn)的get方式。 這種開發(fā)方式我認(rèn)為seam的目的是想屏蔽與頁(yè)面不必要的關(guān)系細(xì)節(jié),讓開發(fā)只需要重視真正的業(yè)務(wù),是一個(gè)標(biāo)準(zhǔn)的面向?qū)ο笫浇Y(jié)構(gòu),當(dāng)jsf的體系結(jié)構(gòu)的不斷優(yōu)化,類似這種開發(fā)方式我想會(huì)越來(lái)越有用。
4. @RequestParameter是個(gè)很有用的注釋,它自動(dòng)把當(dāng)前屬性和頁(yè)面同名的request提交值綁定在一起,雖然這樣使用違背了jsf所追求的面向?qū)ο蠡?,http透明化,但是實(shí)際開發(fā)中會(huì)后很多意想不到的情況,有時(shí)候在集成式頁(yè)面這樣的做法會(huì)很有用,當(dāng)你的頁(yè)面中不僅僅有jsf標(biāo)簽就清楚了!
seam的其他方面問題我會(huì)抽空整理一下,seam目前也是在不斷更新當(dāng)中,明年出臺(tái)的webBeans規(guī)范的前身就是seam,其實(shí)我更關(guān)注的是seam在整個(gè)j2ee體系中的角色,它到底是想替代struts的application?還是想替代spring的manager?也許有更多的想法!