隨着CDI的portlet集成庫的放出,我們可以在JSF portlet中通過Portlet橋,利用CDI帶來的巨大優點。
怎麼使用?
除了通常的Portlet橋依賴以外,在portlet中使用CDI還需要:
- 在項目中添加以下依賴包:
<dependency>
<groupId>org.gatein</groupId>
<artifactId>cdi-portlet-integration</artifactId>
<version>1.0.2.Final</version>
</dependency>
- 在WAR包的WEB-INF目錄下,新增一個空的beans.xml文件。
- 在portlet.xml中,添加以下過濾器的定義:
<filter>
<filter-name>PortletCDIFilter</filter-name>
<filter-class>org.gatein.cdi.PortletCDIFilter</filter-class>
<lifecycle>ACTION_PHASE</lifecycle>
<lifecycle>EVENT_PHASE</lifecycle>
<lifecycle>RENDER_PHASE</lifecycle>
<lifecycle>RESOURCE_PHASE</lifecycle>
</filter>
<filter-mapping>
<filter-name>PortletCDIFilter</filter-name>
<portlet-name>yourPortletName</portlet-name>
</filter-mapping>
PortletCIDFilter只包括接收到的portlet請求可以使用CDI。如果你的程序代碼框架需要處理portlet響應,則需要使用即可以處理請求又能夠處理響應的PortletCDIResponseFilter來代替。@RequestScoped
使用此作用域的bean在portlet中的行爲與常規的JSF不同。在portelt中,設定爲ActionRequest的bean類,其中任何修改的內容都無法到達portlet生命週期的其他階段,包括RenderRequest。所以,建議不要一個JSF的portlet中的CDI bean類中,使用此作用域。推薦使用GateIn 3.6.0 Final中新增的@PortletLifecycleScoped。這個新的作用域允許爲了渲染portlet,在一個action裏面,設置你想要的數據;並且可以從ActionRequest到RenderRequest階段保持Bean的實體。
@ConversationScoped
臨時會話跟一個標記爲@RequestScoped的Bean類具有相同的行爲。因此,不推薦爲渲染JSF portlet而讓數據可用。
預計JSF portlet會提供對長會話的支持,但是,仍然有一些問題需要注意:
- 在RenderRequest階段,結束一個長會話時,將導致接下來的portlet渲染出現一個ConversationNotFoundException。這是因爲portlet渲染所觸發的url,包含有cid參數;CDI據此參數確定是創建一個長會話還是一個臨時會話。如果會話終結時參數仍存在,那麼在下次portlet渲染時,將會試圖重新啓動結束該會話。
- 使用AJAX來開始或者結束一個長會話是不錯的選擇。我們需要重新渲染包括URL在內的所有portlet組件,從而讓CDI知道我們點擊一個鏈接或者按鈕所使用的會話。如果不更新URL,鏈接有可能被賦予一箇舊的cid值,從而導致ConversationNotFoundException,或者直接就沒有cid,導致所有的調用都是臨時會話。
GateIn Scopes
最近,在GateIn 3.6.0 Final版本中提供了兩個新的作用域:@PortletLifecycleScoped與@PortletRedisplayScoped。這兩個作用域在JSF portlet中非常實用,並且可以跟其他的CDI作用域的bean類進行無縫交互。這些作用域將在GateIn的博客文章中展開討論。
希望這篇文章能夠指出在JSF portlet開發中,使用CDI時的一些常見陷阱。