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

12 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");
Run Code Online (Sandbox Code Playgroud)

正如Matt Handy在他的回答中提到的,我使用了Flash.setKeepMessages(true); 但它似乎不适用于ExternalContext.redirect.(虽然通过从bean的action方法返回页面名称来重定向时它可以工作.)

现在我如何添加FacesMessage以便它在重定向(scenario.xhtml)页面中可见?

Bal*_*usC 18

这似乎是一个时间问题.在preRenderView事件期间调用此侦听器方法.根据ELFlash(Mojarra的Flash实现返回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);
}
Run Code Online (Sandbox Code Playgroud)

maybeWriteCookie当FLASH COOKIE中,需要通过第二次(即当反过来重定向页面重定向到另一个页面)通过将只设置cookie.

这是一个不幸的角落案例.这种ELFlash逻辑是有道理的,但这不是你真正想要的.基本上你需要在INVOKE_APPLICATION阶段期间添加消息.然而,没有这样的事件postInvokeAction.使用新的JSF 2.2 <f:viewAction>标记应该是可能的,因为它在调用应用程序阶段时确实运行.

<f:viewAction action="#{bean.onload}" />
Run Code Online (Sandbox Code Playgroud)

只要你还没有使用JSF 2.2,你就需要寻找其他方法.最简单的方法是创建自定义ComponentSystemEvent.

@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {

    public PostInvokeActionEvent(UIComponent component) {
        super(component);
    }

}
Run Code Online (Sandbox Code Playgroud)

现在你需要一个钩子来发布这个事件.最明智的地方是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());
    }

}
Run Code Online (Sandbox Code Playgroud)

如果你在下面注册它 faces-config.xml

<lifecycle>
    <phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
Run Code Online (Sandbox Code Playgroud)

那么你将能够如下使用新事件

<f:event type="postInvokeAction" listener="#{bean.onload}" />
Run Code Online (Sandbox Code Playgroud)

更新此功能也可以在JSF实用程序库OmniFaces中使用,因此您不需要自制一个和另一个.另请参见InvokeActionEventListener展示示例.

  • 仅供参考:[OmniFaces](http://code.google.com/p/omnifaces/)中添加了"<f:event>"的新"preInvokeAction"和"postInvokeAction"事件.它将来会在1.1版本中出现. (2认同)

Mat*_*ndy 16

使用闪存将邮件保留在重定向上.

重定向之前,将这两行添加到代码中:

FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
Run Code Online (Sandbox Code Playgroud)

请注意,Mojarra的闪存范围实现存在一些问题.如果您使用它,请记住这一点.

  • 只有当它在同一条路径中时才有效,如前一个问题所述.还要确保你拥有最新的Mojarra. (3认同)
  • @BalusC当我从action方法返回faces-redirect = true的页面名称时这是有效的.但是当我使用context.redirect()时,重定向页面上不会显示消息. (2认同)