3

我有一个非常简单的应用程序,在 WebLogic 10.3.2 (11g)、Seam 2.2.0.GA 上只有 2 个页面。我每个都有一个命令按钮,它可以在发布后重定向到另一个。这很好用,因为我在地址栏中看到了当前页面的 URL。

但是,即使我没有定义长时间运行的对话,在随机点击次数之后,并且 - 我认为 - 在随机数秒(~10s - 60s)之后,我在这篇文章的末尾得到了一个可爱的例外。

现在,如果我理解了重定向时临时对话是如何工作的:

  1. 当我第一次看到我的应用程序时,url 是http://localhost:7001/myapp
  2. 当我单击 pageA.xhtml 中的按钮时,我最终会出现“pageB.xhtml?cid=26”。这是正常的,因为 Seam 将第一个请求的临时会话延长到重定向的 renderResponse 阶段。因此,它使用扩展临时对话的 cid(对话 ID)来查找任何传播的参数。

  3. 当我单击 pageB.xhtml 中的按钮时,我最终进入 pageA.xhtml?cid=26

新的扩展临时对话也使用了相同的 cid。这是正常的,因为对话在上一个重定向后的帖子结束时结束,而不是数字 26 可以免费用作 cid。

这一切都正确吗?如果是,为什么会发生这种情况:如果我重新输入应用程序的家庭地址(显示 pageA)并重新单击,我最终会出现 pageB.xhtml?cid=29,它与 26 不同。但是 26 已经结束在上一个 RenderResponse 阶段之后,我重新输入了 url。为什么不使用它而不是29?

所以,总结,2个问题:

  1. 即使我没有开始任何长时间的对话,为什么会出现异常?
  2. cid到底发生了什么?它是在什么基础上改变的?

干杯,

更新:

附加信息:我在页面 A 中使用这样的 h:commandButtons:

<h:commandButton action="showPageB" value="Show page B" />

在页面 B

<h:commandButton action="showPageA" value="Show page A" />

导航页A.page.xml:

<page view-id="/pageA.xhtml">
<navigation>
    <rule if-outcome="showPageB">
        <redirect view-id="/pageB.xhtml" />
    </rule>
</navigation>
</page>

和 pageB 非常相似。

至于对话超时,我已将其设置为 1h。请注意,这无关紧要,因为正如我在这里所读到的,它仅用于后台对话。堆栈跟踪如下:

Error 500--Internal Server Error

    java.lang.IllegalArgumentException: Stack must not be null
    at org.jboss.seam.core.ConversationEntry.(ConversationEntry.java:45)
    at org.jboss.seam.core.ConversationEntries.createConversationEntry(ConversationEntries.java:53)
    at org.jboss.seam.core.Manager.createConversationEntry(Manager.java:664)
    at org.jboss.seam.core.Manager.beforeRedirect(Manager.java:836)
    at org.jboss.seam.faces.FacesManager.beforeRedirect(FacesManager.java:66)
    at org.jboss.seam.faces.FacesManager.redirect(FacesManager.java:182)
    at org.jboss.seam.faces.Navigator.redirect(Navigator.java:55)
    at org.jboss.seam.navigation.RedirectNavigationHandler.navigate(RedirectNavigationHandler.java:61)
    at org.jboss.seam.navigation.Rule.execute(Rule.java:101)
    at org.jboss.seam.navigation.Navigation.navigate(Navigation.java:58)
    at org.jboss.seam.navigation.Pages.navigate(Pages.java:203)
    at org.jboss.seam.jsf.SeamNavigationHandler.handleNavigation(SeamNavigationHandler.java:42)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:130)
    at javax.faces.component.UICommand.broadcast(UICommand.java:387)
    at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:324)
    at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:299)
    at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:256)
    at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:469)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:530)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
    at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
    at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
    at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
    at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
    at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3592)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2202)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2108)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1432)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
4

3 回答 3

1

首先,在尝试调试问题时查看相关代码和堆栈跟踪总是有帮助的。

因此,我无法回答您的第一个问题。但是,我将尝试解释对话模型的工作原理。

这是来自 Seam in Action 的书:

@ScopeType.EVENT = Goes from Restore View to Render Response, but not redirect @ScopeType.CONVERSATION = Goes from Restore VIew to Render Response, and redirect. If long-running conversation, then it spans multiple JSF life cycles.

所以想象一下,你在里面a.xhtml按下一个按钮,它将获取ComponentA并填充一些数据。您要在b.xhtml ie 中注入和使用的这个组件:

Push commandbutton in a.xhtml performing post, putting some data in ComponentA 现在你重定向到下一页(b.xhtml),它使用ComponentA

@Name("componentB")
@Scope(ScopeType.CONVERSATION)
public class ComponentB {
    @In(create=true)
    ComponentA componentA; //OK
}

因此,如果您现在按另一个按钮而不是b.xhtml期望能够ComponentA再次注入,那将失败。IE:

@Name("componentC")
@Scope(ScopeType.CONVERSATION)
public class ComponentC {
    @In(create=true)
    ComponentA componentA; //Injection of the component you really want fails (you will get default component)
}

所以现在在后台,seam 为你创建了一个新的 cid,结束了之前的 cid,因为对话范围的组件只能处理一个请求。

于 2010-04-13T13:50:41.650 回答
1

在查看您的 StackTrace 和您的用例之后(随机点击次数后)

让我们看看 FacesManages.beforeRedirect(如您的 StackTrace 所示)文档

在浏览器重定向期间临时将临时对话提升为长时间运行的对话

现在,让我们看一段 beforeRedirect 方法的代码

if (isDifferentConversationId(currentPage, targetPage))
    updateCurrentConversationId(targetPage.getConversationId());

...

updateCurrentConversationId 负责创建不能为空的 Stack再次查看您的 StackTrace

public void updateCurrentConversationId(String id) {
    if (id != null && id.equals(currentConversationId)) {
     // The conversation id has not changed, do nothing       
     return;
  }

在上面显示的代码之后,您的堆栈将被创建。所以我想对话ID没有改变,因为浏览器重定向的持续时间(由随机点击次数引起)甚至是处理从一个页面重定向到另一个页面的导航时的Seam错误,反之亦然

为每个页面规则尝试以下一个(请参阅 timeout="0")

<page view-id="/pageA.xhtml" timeout="0">
    <navigation>
        <rule if-outcome="showPageB">
            <redirect view-id="/pageB.xhtml" />
        </rule>
    </navigation>
</page>

我希望现在它工作正常!但是,如果不是,现在,你知道为什么你会得到你的例外

更新

尝试 <end-conversation/> 作为解决方法(对于每个页面)

<page view-id="/pageA.xhtml">
    <navigation>
        <rule if-outcome="showPageB">
            <end-conversation/>
            <redirect view-id="/pageB.xhtml" />
        </rule>
    </navigation>
</page>

或(见重定向前)

<page view-id="/pageA.xhtml">
    <navigation>
        <rule if-outcome="showPageB">
            <end-conversation before-redirect="true"/>
            <redirect view-id="/pageB.xhtml" />
        </rule>
    </navigation>
</page>

现在我希望它能正常工作!

编辑

正如 beforeRedirect 方法所说

在浏览器重定向期间临时将临时对话提升为长时间运行的对话。重定向后,对话将降级为临时对话。

它解释了为什么当您转到 pageB 时 #{conversation.longRunning} 输出 true。由重定向引起的“长期对话”应在渲染响应阶段后销毁。

当使用重定向时,Seam 将会话 id 参数附加到 URL。

接缝行动书说

在 Seam 生命周期的开始,Seam在 URL 参数中查找会话 id

但是因为当您返回 pageA 时,您再次看到相同的会话 id 参数,我想Seam 只是在 url 不包含任何人时创建一个新参数。而且因为每个长时间运行的对话都有自己的超时时间,所以你的长时间运行的对话会保持活跃。

要验证我所说的是否属实,请执行以下操作

  • 将全局超时时间减少到五秒(5000 毫秒)

...

<core:manager conversation-timeout="5000"/>

对于每个页面,查看 #{conversation.timeout} 输出的内容。我希望看到像 5 秒或 5000 毫秒这样的东西。等待超过 5 秒(约 10 秒),然后按下按钮再次重定向。并查看对话 id 参数是否已更改。

于 2010-04-13T15:27:40.650 回答
0

您早就应该提供该信息。现在更清楚问题是什么了。

首先,您不应该将 commandButton 与这样的空操作一起使用。当您在 pages.xml 中编写以下内容时:

<page view-id="/pageA.xhtml">
<navigation>
    <rule if-outcome="showPageB">
        <redirect view-id="/pageB.xhtml" />
    </rule>
</navigation>
</page>

这通常意味着您有一些返回 showPageB 的操作,如下所示:

public String someAction() {
    //Do something complex
    return "showPageB";
}

无论如何,回到你的问题。帮自己一个忙,创建一个 Seam 组件。

@Name("myComponent")
public Class MyComponent {

public String showPageB() {
    return "showPageB";
}

public String showPageA() {
    return "showPageA";
}

}

将您的 pages.xml 更改为:

<page view-id="/pageA.xhtml">
<navigation from action="#{myComponent.showPageB}">
    <redirect view-id="/pageB.xhtml" />
</navigation>

<navigation from action="#{myComponent.showPageA}">
    <redirect view-id="/pageA.xhtml" />
</navigation>

<!-- OR you can do like this -->
<navigation from action="#{myComponent.showPageB}">
    <rule if-outcome="showPageA">
        <redirect view-id="/pageA.xhtml" />
    </rule>
    <rule if-outcome="showPageB">
        <redirect view-id="/pageA.xhtml" />
    </rule>
</navigation>
</page>

然后将 xhtml 更改h:commandButton

<h:commandButton action="#{myComponent.showPageA}" value="showA"/>
<h:commandButton action="#{myComponent.showPageB}" value="showB"/>
于 2010-04-14T07:57:10.470 回答