2013-03-13 93 views
3

我的項目正在使用JSF2.0和CDI。對於一頁,我希望我的支持bean匹配頁面的使用壽命。 @ViewScoped似乎是一個完美的選擇,但它不是CDI的一部分,然後讓我們的解決方案不一致。然後我的下一個選擇是CDI @ConversationScoped。對我來說,標記對話邊界的唯一方法是通過conversation.begin和conversation.end的程序方式(我已經使用Seam 2.x,可以使用註釋來標記對話邊界)。我的頁面與全球導航坐在一個共同的佈局中,這意味着有「無限」的方式可以離開我的頁面。我如何確保以用戶可能選擇的方式結束對話(例如,單擊完全在我的支持bean控制之外的全局navi選項)?我希望該解決方案不會將代碼傳播到其他模塊;如果這是不可避免的,我希望它能夠以交叉的方式實施(AOP)。如何幹淨地結束CDI @ConversationScoped

回答

4

這可以通過自定義ConfigurableNavigationHandler來實現。

  1. 實施JSF NavigationHandler

    public class NavigationHandlerTest extends ConfigurableNavigationHandler { 
    
    private NavigationHandlerTest concreteHandler; 
    
    public NavigationHandlerTest(NavigationHandler concreteHandler) { 
         this.concreteHandler = concreteHandler; 
    } 
    
    
    @Override 
    public void handleNavigation(FacesContext context, String fromAction, String outcome) 
    { 
        //here, check where navigation is coming from and based on that, retrieve the CDI bean and kill the conversation 
        if(fromAction.equals("someAction"){ 
        BeanManager theBeanManager = getBeanManager(context); 
        Bean bean = theBeanManager.getBeans("yourCDIBean").iterator().next() 
        CreationalContext ctx = theBeanManager.createCreationalContext(bean); 
        MyBeanType o = theBeanManager.getReference(bean, bean.getClass(), ctx); //retrieve the bean from the manager by name. You're guaranteed to retrieve only one of the same name; 
        o.getConversation.end(); //end the conversation from the bean reference 
         } 
    
        //proceed with normal navigation 
        concreteHandler.handleNavigation(context, fromAction, outcome); 
    
    } 
    
    //This method provides access to the cdi bean manager. You need it to be able to 
    //gain access to the cdi bean and from that to the injected conversation instance 
    public BeanManager getBeanManager(FacesContext facesContext){ 
        BeanManager cdiBeanManager = (BeanManager)((ServletContext) facesContext.getExternalContext().getContext()).getAttribute("javax.enterprise.inject.spi.BeanManager"); 
        return cdiBeanManager; 
    } 
    
    
        } 
    
  2. 註冊在您的自定義導航處理程序faces-config.xml中

    <application> 
        <navigation-handler>com.foo.bar.NavigationHandlerTest</navigation-handler> 
    </application> 
    

這種做法是集中式和微創

+0

它的工作原理。謝謝! – chaoshangfei 2013-03-19 23:28:31

+0

@FangZhang非常歡迎 – kolossus 2013-03-20 01:15:06

+0

這是一個醜陋的解決方法。我會使用CODI-對話。 – 2013-11-18 11:04:19

0

據我所知 - 你不能。在JSF中,確定鏈接是否在當前或新選項卡中打開(對於新的需要離開會話激活)幾乎是不可能的(很難)。

但好消息 - 對話將在閒置10分鐘後自動關閉(默認情況下)。

+0

好吧,拋開設計問題。從技術上講,您可以使所有導航請求都通過導航服務對象。每個對話都有一個ID。一旦打開目標頁面,我們可以將該ID保存在服務對象中,如果任何以下導航請求不是針對目標頁面的,則我們知道我們需要結束對話。由於CDI有些基於Seam,我希望能有一個更優雅的解決方案。 – chaoshangfei 2013-03-13 22:45:17

+0

來自CODI的客戶端窗口處理程序可以正確檢測新的選項卡/窗口。 – 2013-11-18 11:06:03