【问题标题】:Can't keep faces message after navigation from preRender从 preRender 导航后无法保留面孔消息
【发布时间】:2012-10-30 17:36:13
【问题描述】:

在我的页面预渲染代码中,我添加了面孔消息,然后导航到另一个页面,如下所示:

if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
                .setKeepMessages(true);
navigateActionListener("myoutcome");
}

添加消息和导航的util方法有:

public static String getClientId(String componentId)
    {
        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot root = context.getViewRoot();

        UIComponent c = findComponent(root, componentId);
        return c.getClientId(context);
    }

    public static UIComponent findComponent(UIComponent c, String id)
    {
        if (id.equals(c.getId())) { return c; }
        Iterator<UIComponent> kids = c.getFacetsAndChildren();
        while (kids.hasNext())
        {
            UIComponent found = findComponent(kids.next(), id);
            if (found != null) { return found; }
        }
        return null;
    }

    /**
     * @param componentId
     *            : the id for the jsf/primefaces component without formId:
     *            prefix. <br>
     *            if you use null then the message will be added to the
     *            h:messages component.
     **/
    public static void addMessageToComponent(String componentId, String message)
    {

        if (componentId != null)
            componentId = GeneralUtils.getClientId(componentId);
        FacesContext.getCurrentInstance().addMessage(componentId,
                new FacesMessage(message));
    }

public static void navigateActionListener(String outcome)
    {
        FacesContext context = FacesContext.getCurrentInstance();
        NavigationHandler navigator = context.getApplication()
                .getNavigationHandler();
        navigator.handleNavigation(context, null, outcome);
    }

但消息未保存,因此重定向后不会出现。

请告知如何解决。

【问题讨论】:

    标签: jsf jsf-2


    【解决方案1】:

    preRenderView 事件在RENDER_RESPONSE 阶段的最开始运行。指示Flash 范围保留消息为时已晚。您最迟可以在INVOKE_APPLICATION 阶段执行此操作。

    由于没有标准的 JSF 组件系统事件,您需要自制一个:

    @NamedEvent(shortName="postInvokeAction")
    public class PostInvokeActionEvent extends ComponentSystemEvent {
    
        public PostInvokeActionEvent(UIComponent component) {
            super(component);
        }
    
    }
    

    要发布此内容,您需要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.init}" />
    

    你只需要确保你至少有一个&lt;f:viewParam&gt;,否则JSF根本不会进入被调用阶段。

    JSF 实用程序库OmniFaces 已经支持此事件和开箱即用的preInvokeAction 事件。另请参阅the showcase page,它还演示了如何设置面部消息以进行重定向。

    【讨论】:

    • postInvokeAction 将等同于 preRenderView 事件?
    • 我想要完成的是当用户对页面发出获取请求时,进行检查,如果失败则添加错误消息然后导航到另一个页面,所以我在 preRenderView 中执行此逻辑。这个新事件会产生同样的行为吗?
    • 它们不一样。 postInvokeAction 在调用操作阶段结束时运行,这非常适合在 Flash 范围内设置消息。 preRenderView 在渲染响应阶段的开始运行,这对于在 Flash 范围内设置消息为时已晚。这就是这个答案的重点。
    • 我迷路了。我可以在这个活动中进行检查吗?它在渲染页面之前运行吗?
    • 我也不懂你。在将上述代码添加到您的环境(或将 OmniFaces JAR 文件放在 /WEB-INF/lib 中)之后,您只需将 &lt;f:event type="preRenderView"&gt; 替换为 &lt;f:event type="postInvokeAction"&gt; .展示页面包含一个演示。
    猜你喜欢
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    相关资源
    最近更新 更多