Jsf Can';t从preRender导航后保留faces消息

Jsf Can';t从preRender导航后保留faces消息,jsf,jsf-2,Jsf,Jsf 2,在页面的预渲染代码中,我添加了faces消息,然后导航到另一个页面,如下所示: if(error){ addMessageToComponent(null,"AN ERROR HAS OCCURRED"); FacesContext.getCurrentInstance().getExternalContext().getFlash() .setKeepMessages(true); navigateActionListener("myoutcome"); }

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

if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
                .setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />
用于添加消息和导航的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);
    }
公共静态字符串getClientId(字符串组件ID)
{
FacesContext context=FacesContext.getCurrentInstance();
UIViewRoot root=context.getViewRoot();
UIComponent c=findComponent(根,componentId);
返回c.getClientId(上下文);
}
公共静态UIComponent findComponent(UIComponent c,字符串id)
{
if(id.equals(c.getId()){返回c;}
迭代器kids=c.getFacetsAndChildren();
while(kids.hasNext())
{
UIComponent found=findComponent(kids.next(),id);
if(found!=null){return found;}
}
返回null;
}
/**
*@param-componentId
*:不带formId的jsf/primefaces组件的id:
*前缀
*如果使用null,则消息将添加到 *h:消息组件。 **/ 公共静态void addMessageToComponent(字符串组件ID,字符串消息) { if(componentId!=null) componentId=GeneralUtils.getClientId(componentId); FacesContext.getCurrentInstance().addMessage(组件ID, 新面孔信息(信息)); } 公共静态void navigateActionListener(字符串结果) { FacesContext context=FacesContext.getCurrentInstance(); NavigationHandler navigator=context.getApplication() .getNavigationHandler(); 导航器.手动导航(上下文,空,结果); }
但是消息不会被保存,因此重定向后它不会出现


请建议如何解决此问题。

渲染响应
阶段的最开始运行
预渲染视图
事件。现在指示
Flash
范围保存消息已经太晚了。您最迟可以在
调用应用程序
阶段执行此操作

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

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

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

}
要发布此内容,您需要一个
相位侦听器

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>

com.example.PostInvokeActionListener
您可以按如下方式使用新事件:

if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
                .setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />

您只需要确保您至少有一个
,否则JSF根本不会进入调用阶段


JSF实用程序库已经支持此事件和
preInvokeAction
事件。另请参见,其中还演示了为重定向设置facesmessage。

预渲染视图事件在
渲染响应
阶段的最开始运行。现在指示
Flash
范围保存消息已经太晚了。您最迟可以在
调用应用程序
阶段执行此操作

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

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

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

}
要发布此内容,您需要一个
相位侦听器

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>

com.example.PostInvokeActionListener
您可以按如下方式使用新事件:

if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
                .setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />

您只需要确保您至少有一个
,否则JSF根本不会进入调用阶段


JSF实用程序库已经支持此事件和
preInvokeAction
事件。另请参见,其中还演示了如何为重定向设置facesmessage。

postInvokeAction将等效于preRenderView事件?我要完成的是,当用户对页面发出get请求时,进行检查,如果失败,则添加错误消息,然后导航到另一个页面,因此我在preRenderView中执行此逻辑。这个新事件会产生同样的行为吗?它们不一样。
postInvokeAction
在调用操作阶段结束时运行,这是在flash范围内设置消息的最佳时机。
preRenderView
在渲染响应阶段的开始运行,这对于在flash范围内设置消息来说太晚了。这就是这个答案的全部要点。我在这里迷路了。我能在这个事件中进行检查吗?它在呈现页面之前运行吗?我也不明白你的意思。在将上述代码添加到您的环境(或将OmniFaces JAR文件放置在
/WEB-INF/lib
中)之后,您只需将
替换为
,如果您没有任何代码,则在必要时添加一个虚拟
。showcase页面包含一个演示。postInvokeAction将等效于preRenderView事件?我要完成的是,当用户对页面发出get请求时,进行检查,如果失败,则添加错误消息,然后导航到另一个页面,因此我在preRenderView中执行此逻辑。这个新事件会产生同样的行为吗?它们不一样。
postInvokeAction
在调用操作阶段结束时运行,这是在flash范围内设置消息的最佳时机。
preRenderView
在渲染响应阶段的开始运行,这对于在flash范围内设置消息来说太晚了。这就是这个答案的全部要点。我在这里迷路了。我能在这个事件中进行检查吗?它在呈现页面之前运行吗?我也不明白你的意思。在将上述代码添加到您的环境(或将OmniFaces JAR文件放置在
/WEB-INF/lib
中)之后,您只需将
替换为
,如果您没有任何代码,则在必要时添加一个虚拟
。showcase页面包含一个演示。