JSF FlashScope无法处理FacesContext重定向

时间:2012-11-22 12:59:27

标签: jsf jsf-2

我在使用JSF的FlashScope时遇到问题,请注意我知道重定向应指向与调用页面相同的基本路径。

我的情况是,当客户端点击他/她的电子邮件中的链接时,该操作将被初始化,然后它将加载带有支持bean的.xhtml(具有preRenderView事件)页面以检查传递的参数。当参数错误时,它必须重定向到带有消息的新页面。

观点:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">

    <f:metadata>
        <f:viewParam name="dummy" />
        <f:event listener="#{signupMaterialBean.initFromContext()}"
            type="preRenderView"></f:event>
    </f:metadata>

    <h:outputText value="#{signupMaterialBean.html}" escape="false"></h:outputText>

</ui:composition>

支持Bean:

public void initFromContext() {
    try {
        Map<String, String> params = facesContext.getExternalContext()
                .getRequestParameterMap();
        ...
    } catch (NullPointerException e) {      
        try {
            Message message = new Message();
            String msg = "Invalid parameters";
            message.setMessage(msg);

            JSFUtils.flashScope().put("message", message);

            facesContext.getExternalContext().redirect("message.xhtml");
            facesContext.responseComplete();
        } catch (IOException ioe) {
        }
    } catch (IOException e) {
    }
}

重定向有效,但FlashScope中的消息保存消失了。知道闪存范围被删除的原因或其他方法吗?

message.xhtml     

    <ui:define name="head"></ui:define>

    <ui:define name="content">
        <div class="box-middle-content faded">
            <div class="message">
                <h:outputText escape="false" value="#{flash.message.message}"></h:outputText>
                <br />
                <p>
                    <h:outputText value="#{msgs['message.footer']}" escape="false" />
                </p>
            </div>
        </div>
    </ui:define>
</ui:composition>

JSFUtils

public class JSFUtils {
    public static Flash flashScope() {
        return (FacesContext.getCurrentInstance().getExternalContext()
                .getFlash());
    }
}

更新了视图:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui"
    xmlns:of="http://omnifaces.org/functions">

    <f:metadata>
        <f:viewParam name="dummy"></f:viewParam>
        <f:event type="postInvokeAction"
            listener="#{signupMaterialBean.initFromContext}" />
    </f:metadata>

    <h:outputText value="#{signupMaterialBean.html}" escape="false"></h:outputText>

</ui:composition>

1 个答案:

答案 0 :(得分:4)

<f:event type="preRenderView">设置闪存范围属性为时已晚。当JSF当前处于渲染响应阶段时,无法创建闪存范围。您基本上需要在渲染响应阶段之前设置闪存范围属性。尽管名称为preRenderView,但此事件实际上是在(渲染响应阶段的最开始)期间触发的

您基本上需要在INVOKE_ACTION阶段调用侦听器方法。因为没有标准的<f:event>类型,所以你需要自己生成一个。在这个答案中详细概述了这一点:Can't keep faces message after navigation from preRender

你最终想结束:

<f:event listener="#{signupMaterialBean.initFromContext()}"
         type="postInvokeAction" />

请注意,此事件已由OmniFaces提供。另请参阅the InvokeActionEventListener showcase page来处理这个问题。


对具体问题

无关NullPointerException上的捕获是一个巨大的代码味道。不要捕获这样的运行时异常。通过执行if (foo != null)等空值检查来阻止它们。此外IOException上的那些空捕获也非常糟糕。将它们全部删除,只需将throws IOException添加到方法中即可。

此外,自Mojarra 2.1.14以来,重定向路径问题已得到修复。因此,从该版本开始,您可以安全地重定向到不同的基本路径。