我正在使用 ExternalContext.redirect(String); 方法将用户重定向到另一个页面:
FacesContext.getCurrentInstance().addMessage(new FacesMessage("Bla bla bla..."));
FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true);
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/scenario.xhtml");
正如Matt Handy在他的回答中提到的,我使用了 Flash.setKeepMessages(true); ,但它似乎不适用于ExternalContext.redirect。 (虽然通过从bean的action方法返回页面名称来重定向时它可以正常工作。)
现在我如何添加FacesMessage以便它在重定向(scenario.xhtml)页面中可见?
答案 0 :(得分:17)
这似乎是一个时间问题。在preRenderView
事件期间调用此侦听器方法。根据{{1}}的源代码(由ELFlash
返回的Mojarra的Flash
实现),事实证明,当您当前坐在渲染响应中时,它不会设置Flash Cookie尚未为当前请求设置阶段和闪存cookie:
以下是ExternalContext#getFlash()
的相关行:
ELFlash
if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
flashInfo = flashManager.getPreviousRequestFlashInfo();
} else {
flashInfo = flashManager.getNextRequestFlashInfo(this, true);
maybeWriteCookie(context, flashManager);
}
只会在需要第二次传递flash cookie时设置cookie(即重定向页面又会重定向到另一个页面)。
这是一个不幸的角落案例。这个maybeWriteCookie
逻辑是有道理的,但这不是你真正想要的。 基本上您需要在ELFlash
阶段添加消息。但是没有INVOKE_APPLICATION
这样的事件。使用新的JSF 2.2 postInvokeAction
标记应该是可能的,因为它在调用应用程序阶段时确实运行。
<f:viewAction>
只要你还没有使用JSF 2.2,你就需要寻找替代方法。最简单的方法是创建自定义ComponentSystemEvent
。
<f:viewAction action="#{bean.onload}" />
现在你需要一个钩子来发布这个事件。最明智的地方是在@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
阶段之后进行PhaseListener
聆听。
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>
更新这也可以在JSF实用程序库OmniFaces中使用,因此您不需要自制一个和另一个。另请参阅InvokeActionEventListener
showcase example。
答案 1 :(得分:16)
使用闪存将邮件保留在重定向上。
在重定向之前,将这两行添加到代码中:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
请注意,some issues with Mojarra's flash scope implementation有{{3}}。如果您使用它,请记住这一点。
答案 2 :(得分:-2)
使用Matt Handy的示例作为参考,我创建了下面的方法,该方法对我来说非常有效。
public static void Message(String message) {
FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_INFO, mensagem, null);
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
context.addMessage(null, fm);
}