当前位置 : 主页 > 网页制作 > HTTP/TCP >

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

来源:互联网 收集:自由互联 发布时间:2021-06-16
我正在使用ExternalContext.redirect(String);将用户重定向到另一个页面的方法: FacesContext.getCurrentInstance().addMessage(new FacesMessage("Bla bla bla..."));FacesContext.getCurrentInstance().getExternalContext().getFlas
我正在使用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)页面中可见?

这似乎是一个时间问题.在preRenderView事件期间调用此侦听器方法.根据ELFlash的源代码(由ExternalContext#getFlash()返回的Mojarra的 Flash实现),当你当前处于渲染响应阶段并且flash cookie没有时,它将不会设置flash cookie已为当前请求设置:

以下是ELFlash的相关行:

if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
    flashInfo = flashManager.getPreviousRequestFlashInfo();
} else {
    flashInfo = flashManager.getNextRequestFlashInfo(this, true);
    maybeWriteCookie(context, flashManager);
}

maybeWriteCookie只会在需要第二次传递flash cookie时设置cookie(即当重定向页面又重定向到另一个页面时).

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

<f:viewAction action="#{bean.onload}" />

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

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

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

}

现在你需要一个钩子来发布这个事件.最明智的地方是在INVOKE_APPLICATION阶段后监听PhaseListener.

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}" />

JSF实用程序库OmniFaces中也提供了更新,因此您不需要自制一个和另一个.另见InvokeActionEventListener showcase example.

网友评论