这似乎是一个时间问题。该侦听器方法在preRenderView
事件。根据源代码ELFlash
(莫贾拉的Flash http://docs.oracle.com/javaee/6/api/javax/faces/context/Flash.html返回的实现ExternalContext#getFlash()
)事实证明,当您当前处于渲染响应阶段并且尚未为当前请求设置 flash cookie 时,它不会设置 flash cookie:
以下是相关行ELFlash
:
if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
flashInfo = flashManager.getPreviousRequestFlashInfo();
} else {
flashInfo = flashManager.getNextRequestFlashInfo(this, true);
maybeWriteCookie(context, flashManager);
}
The maybeWriteCookie
仅当需要第二次传递 flash cookie 时(即,当重定向的页面又重定向到另一个页面时)才会设置 cookie。
这是一个不幸的极端案例。这ELFlash
逻辑是有道理的,但这不是你真正想要的。基本上您需要在期间添加消息INVOKE_APPLICATION
相代替。然而,没有这样的事件postInvokeAction
。使用新的 JSF 2.2<f:viewAction>
标记它应该是可能的,因为它确实在调用应用程序阶段运行。
<f:viewAction action="#{bean.onload}" />
只要您还没有使用 JSF 2.2,您就需要寻找替代方法。最简单的方法是创建一个自定义ComponentSystemEvent http://docs.oracle.com/javaee/6/api/javax/faces/event/ComponentSystemEvent.html.
@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
现在您需要在某个地方有一个钩子来发布此事件。最明智的地方是PhaseListener http://docs.oracle.com/javaee/6/api/javax/faces/event/PhaseListener.html在阶段后收听INVOKE_APPLICATION
.
public class PostInvokeActionListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
}
}
如果您按如下方式注册faces-config.xml
<lifecycle>
<phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
然后您就可以使用新事件,如下所示
<f:event type="postInvokeAction" listener="#{bean.onload}" />
Update这也可以在 JSF 实用程序库中找到OmniFaces http://omnifaces.org,所以你不需要自制一个和另一个。另请参阅InvokeActionEventListener展示示例 http://showcase.omnifaces.org/eventlisteners/InvokeActionEventListener.