4

我有一个@ConversationScoped bean,带有一个 start 方法,如下所示:

@PostConstruct
public void start() {
    if (conversation.isTransient()) {
        conversation.begin();
        log.debug("conversation.getId(): " + conversation.getId());
    }
}

我的问题是,每次刷新页面时都会启动一个新对话,每次我对 bean 中的方法进行 AJAX 调用时也会启动一个新对话(这是我的主要问题)。

我真正想要发生的是让 sam 对话一直存在,直到我手动调用 conversation.end()。我在这里想念什么?

4

6 回答 6

6

有点题外话,但希望有价值:

我不是 100% 确定 @PostConstruct 是开始对话的正确位置。我宁愿使用这样的面孔事件:

<f:metadata>
        <f:event type="javax.faces.event.PreRenderViewEvent"
                listener="#{myBean.init}" />
</f:metadata>

如果您确定自己不在 JSF-postback 请求中,则开始对话。

public void init() {
       if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
          conversation.begin();
       }
    }

如果你使用 Seam 3,那就更简单了:

<f:metadata>
   <s:viewAction action="#{myBean.init}" if="#{conversation.transient}" />
</f:metadata>
于 2011-05-30T07:24:24.343 回答
4

您是否检查过 (AJAX) 调用是否包含对话 ID 参数 (cid)?

如果缺少此功能,则预计每次通话都会开始新的对话。

于 2011-05-29T13:56:45.683 回答
3

JSR-299 内置 Conversation 的概念有点破旧。至少对于 JSF 应用程序而言。使用@PreRenderViewEvent 基本上会放弃这种方法的所有好处,因为它会使每个@ConversationScoped bean longRunning。

您可以尝试改用 Apache MyFaces CODI @ConversationScoped。CODI 是一个 CDI 扩展库,可以很好地与 Apache OpenWebBeans 以及 Weld 一起使用。它还提供@ViewScoped、@ViewAccessScoped(一种自动对话)和@WindowScoped 上下文。

更多信息:https ://cwiki.apache.org/confluence/display/EXTCDI/Index

于 2011-06-24T22:53:31.647 回答
2

这一切都在文档中:

对话范围处于活动状态:

在任何 JSF 面孔或非面孔请求的所有标准生命周期阶段。

对话上下文提供对与特定对话关联的状态的访问。每个 JSF 请求都有一个关联的对话。该关联由容器根据以下规则自动管理:

任何 JSF 请求都只有一个关联的对话。与 JSF 请求关联的对话在恢复视图阶段开始时确定,并且在请求期间不会更改。

任何对话都处于以下两种状态之一:瞬态或长时间运行。

默认情况下,对话是暂时的 暂时的对话可以通过调用 Conversation.begin() 标记为长时间运行 长时间运行的对话可以通过调用 Conversation.end() 标记为暂时的

所有长时间运行的会话都有一个字符串值的唯一标识符,该标识符可以在会话被标记为长时间运行时由应用程序设置,或者由容器生成。

如果与当前 JSF 请求相关联的会话在 JSF 请求结束时处于瞬态,则它被销毁,并且会话上下文也被销毁。

如果与当前 JSF 请求相关联的会话在 JSF 请求结束时处于长时间运行状态,则它不会被销毁。相反,它可能会根据以下规则传播到其他请求:

与呈现 JSF 视图的请求关联的长时间运行的对话上下文会自动传播到源自该呈现页面的任何面孔请求(JSF 表单提交)。与导致 JSF 重定向(由导航规则或 JSF NavigationHandler 产生的重定向)的请求相关联的长时间运行的对话上下文会自动传播到生成的非人脸请求,以及对同一 URL 的任何其他后续请求。这是通过使用名为 cid 的 GET 请求参数来完成的,该参数包含对话的唯一标识符。通过使用名为 cid 的 GET 请求参数,可以将与请求关联的长时间运行的对话传播到任何非人脸请求,该参数包含对话的唯一标识符。在这种情况下,

当没有对话传播到 JSF 请求时,该请求与新的临时对话相关联。所有长时间运行的对话都被限定在一个特定的 HTTP servlet 会话中,并且可能不会跨越会话边界。在以下情况下,传播的长时间运行的对话无法恢复并与请求重新关联:

当 HTTP servlet 会话无效时,在 servlet service() 方法完成后,在当前会话期间创建的所有长时间运行的会话上下文都将被销毁。允许容器任意销毁与当前没有 JSF 请求相关联的任何长时间运行的对话,以节省资源。

作者:加文·金、皮特·缪尔

于 2011-05-30T07:20:11.113 回答
0

恕我直言,CDI 对话被设计破坏了,struberg 指出了一个有希望的替代方案。在我的应用程序中,我遇到了同样的问题,目前我正在将其重构为 CDI + CODI 1,感觉不错。@ConversationScoped 解决了所有这些问题。在重构我的应用程序时,我可以使用@ViewAccessScoped 解决很多令人讨厌的案例。感谢 struberg 为我们指出它!

于 2011-08-19T17:03:14.947 回答
0

奇怪的是,如果你在 Facelet 中添加一个事件监听器,即使它调用了一个空方法,生成的源的表单动作也会有 'cid' 参数,因此,AJAX 调用不会创建新的对话。如果没有事件侦听器,则“cid”会丢失表单操作。

<f:metadata>
    <f:event listener="#{myBean.dummy}" type="preRenderView" />
</f:metadata>

MyBean.java

public void dummy() {}
于 2013-06-23T03:40:35.247 回答