【问题标题】:How to cleanly end a CDI @ConversationScoped如何干净地结束 CDI @ConversationScoped
【发布时间】:2013-03-01 21:49:23
【问题描述】:

我的项目正在使用 JSF2.0 和 CDI。对于一页,我希望我的支持 bean 与页面的生命周期相匹配。 @ViewScoped 似乎非常合适,但它不是 CDI 的一部分,然后使我们的解决方案不一致。然后我的下一个选择是 CDI @ConversationScoped。在我看来,标记对话边界的唯一方法是通过 conversation.begin 和 conversation.end 的程序方式(我使用过 Seam 2.x,在那里你可以使用注释来标记对话边界)。我的页面位于具有全局导航的通用布局中,这意味着有“无限”的方式可以离开我的页面。无论用户选择哪种方式,我如何确保对话结束(例如,单击完全超出我的支持 bean 控制的全局导航选项)?我希望该解决方案不会将代码传播到其他模块;如果这是不可避免的,我希望它可以以横切方式 (AOP) 实现。

【问题讨论】:

    标签: jakarta-ee jsf-2 cdi


    【解决方案1】:

    据我所知 - 你不能。在 JSF 中,几乎不可能(很难)确定链接是在当前标签还是新标签中打开(对于新标签,您需要保持对话处于活动状态)。

    但好消息 - 闲置 10 分钟后会话将自动关闭(默认情况下)。

    【讨论】:

    • 好吧,把设计问题放在一边。从技术上讲,您可以使所有导航请求都通过导航服务对象。每个对话都有一个 id。一旦目标页面打开,我们可以将id保存在服务对象中,如果任何后续导航请求不是针对目标页面的,那么我们知道我们需要结束对话。由于 CDI 在某种程度上基于 Seam,我希望我能有一个更优雅的解决方案。
    • 您可以尝试创建特殊的 commandLink 而不是简单的 (作为带有“target”参数的一些复合材料)。这样的链接将在某些 @ConversationScoped bean 上调用“closeConversation”方法并将您重定向到“目标”链接...
    • CODI 的客户端窗口处理程序可以正确检测到新的选项卡/窗口。
    【解决方案2】:

    这可以通过自定义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>
      

    这种方法是集中式和微创的

    【讨论】:

    猜你喜欢
    • 2010-10-26
    • 2015-07-28
    • 2013-04-18
    • 2011-12-24
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多