使用ExternalContext.redirect()将面部消息添加到重定向页面

时间:2012-05-15 07:05:44

标签: jsf redirect jsf-2

我正在使用 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)页面中可见?

3 个答案:

答案 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);
}