我有一个非常简单的应用程序,在WebLogic 10.3.2(11g),Seam 2.2.0.GA上只有2页。我在每个中都有一个命令按钮,它会在另一个后面进行重定向。这很有效,因为我在地址栏中看到了当前页面的URL。
但是,即使我已经定义了没有长时间运行的对话,经过随机的点击次数,并且 - 我认为 - 在一个随机的秒数之后(〜 10s - 60s)我在这篇文章的最后得到了一个可爱的例外。
现在,如果我已经理解了重定向时临时对话的工作原理:
当我点击pageA.xhtml中的按钮时,我最终进入“pageB.xhtml?cid = 26”。这是正常的,因为Seam会将第一个请求的临时会话延长到重定向的renderResponse阶段。因此,它使用扩展临时对话的cid(对话ID)来查找任何传播的参数。
当我点击pageB.xhtml中的按钮时,我最终进入pageA.xhtml?cid = 26
同样的cid被赋予新的扩展临时对话。这是正常的,因为会话在之前的重定向后结束时结束,而不是数字26可以作为cid使用。
这一切都正确吗?如果是,为什么会发生这种情况:如果我重新键入应用程序主页地址(显示pageA)并重新点击,我最终会在pageB.xhtml?cid = 29,这是一个不同于26的数字。但是26已经结束在之前的RenderResponse阶段之后,我会重新输入网址。为什么不使用而不是29?
所以,要补充,2个问题:
干杯,
更新
附加信息:我在第A页中使用h:commandButtons:
<h:commandButton action="showPageB" value="Show page B" />
和第B页
<h:commandButton action="showPageA" value="Show page A" />
导航pageA.page.xml:
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
和pageB非常相似。
对于会话超时,我已将其设置为1h。请注意,这是无关紧要的,因为在我阅读here时,它仅用于后台对话。堆栈跟踪如下:
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)
答案 0 :(得分: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
中注入和使用的此组件
即:
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
,那么将会失败。
即:
@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,因为会话范围的组件只能生成一个请求。
答案 1 :(得分:1)
在看到您的StackTrace和您的用例(随机点击次数后)
让我们看看FacesManages.beforeRedirect(如StackTrace所示)文档
在浏览器重定向期间暂时将对话提升为长时间对话
现在,让我们看一下beforeRedirect方法的一些代码
if (isDifferentConversationId(currentPage, targetPage))
updateCurrentConversationId(targetPage.getConversationId());
...
updateCurrentConversationId负责创建堆栈,它必须不为空再次查看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>
我希望现在它运作正常!但是,如果没有,现在,你知道为什么你会得到你的例外
<强>更新强>
尝试&lt;结束对话/&gt;作为解决方法(针对每个页面)
<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方法所说的
暂时在浏览器重定向期间提升与长时间对话的临时对话。重定向后,会话将被降级为临时会话。
1°它解释了为什么#{conversation.longRunning}在转到pageB时输出为true。在渲染响应阶段之后,应该销毁由重定向引起的“长时间运行的对话”。
使用重定向时,Seam会将会话ID paratemer附加到URL。
Seam in Action书中说
在Seam生命周期开始时,Seam在网址参数
中查找会话ID
但是因为当你回到pageA时,你再次看到相同的会话ID参数,我想 Seam只是在网址不包含任何人时创建一个 。而且因为每个长时间运行的对话都有自己的超时时间,所以长时间运行的对话会保持活跃。
要验证我说的是否属实,请执行以下操作
...
<core:manager conversation-timeout="5000"/>
对于每个页面,请查看#{conversation.timeout}输出内容。我希望看到像5秒或5000毫秒的东西。等待超过5秒(约10秒),然后按按钮再次重定向。并查看对话ID参数是否已更改。
答案 2 :(得分: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"/>