jsf-2 - 在 JSF 错误处理程序中使用 ExternalContext.dispatch 会导致页面呈现损坏

标签 jsf-2

简化后,我的错误处理程序如下所示:

@Override
public void handle() throws FacesException {
    Iterator<ExceptionQueuedEvent> unhandledExceptionQueuedEvents = getUnhandledExceptionQueuedEvents().iterator();
    FacesContext context = FacesContext.getCurrentInstance();

    if (unhandledExceptionQueuedEvents.hasNext()) {
        Throwable exception = unhandledExceptionQueuedEvents.next().getContext().getException();
        unhandledExceptionQueuedEvents.remove();
        context.getExternalContext().dispatch("/error.jsf");
    }

    while (unhandledExceptionQueuedEvents.hasNext()) {
        unhandledExceptionQueuedEvents.next();
        unhandledExceptionQueuedEvents.remove();
    }
}

简化的 template.xhtml

<html>
    <f:view>
    <h:head>
    <!-- some stuff here -->
    </h:head>
    <h:body>
        <div id="menu"><!-- menu content --></div>
        <div id="content">
            <ui:insert name="body"></ui:insert>
        </div>
    </h:body>
    </f:view>
</html>

错误.xhtml

<html>
<ui:composition template="/template.xhtml">
    <ui:define name="body">
        ERROR
    </ui:define>
</ui:composition>
</html>

但是在渲染 error.jsf 时,使用 ui:composition 进行模板化会出错。 JSF 一直渲染 template.xhtml 直到 ,然后重新开始渲染模板。结果是一个菜单呈现两次的页面,所有资源再次包含在页面中间。它的开头看起来像这样:

<div id="menu></div>
<div<?xml version="1.0" encoding="UTF-8" ?="">
    <!-- Page included once more -->

这之后是服务器上的无限循环,导致数百万条日志行一遍又一遍地包含以下位

at com.xdin.competence.web.error.ErrorHandler.handleException(ErrorHandler.java:123) [:]
at com.xdin.competence.web.error.ErrorHandler.handle(ErrorHandler.java:108) [:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:115) [:2.0.3-]
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:107) [:2.0.3-]
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114) [:2.0.3-]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:308) [:2.0.3-]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:734) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:541) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:479) [:6.0.0.Final]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:407) [:6.0.0.Final]
at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:542) [:2.0.3-]
at javax.faces.context.ExternalContextWrapper.dispatch(ExternalContextWrapper.java:89) [:2.0.3-]
at org.jboss.seam.faces.environment.org$jboss$weld$bean-jboss$classloader:id="vfs:$$$C:$JBoss$jboss-6$0$0$Final$server$career$deploy$career-portal$war"-ManagedBean-class_org$jboss$seam$faces$environment$SeamExternalContext_$$_WeldClientProxy.dispatch(org$jboss$weld$bean-jboss$classloader:id="vfs:$$$C:$JBoss$jboss-6$0$0$Final$server$career$deploy$career-portal$war"-ManagedBean-class_org$jboss$seam$faces$environment$SeamExternalContext_$$_WeldClientProxy.java) [:3.0.1.Final]

知道原因是什么吗?

最佳答案

您不应使用 ExternalContext#dispatch() 来呈现 JSF View 。它应该只用于转发到非 JSF 资源。您应该改为通过 FacesContext#setViewRoot() 设置所需的 JSF View 并让 JSF 渲染它。

ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, viewId);
context.setViewRoot(viewRoot);
context.renderResponse();

或者,如果您当前已经处于渲染响应中,那么让 JSF 重新渲染它就太晚了。您需要手动构建和呈现新 View 。在这种情况下,将最后一行替换为:

ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(context, viewId);
vdl.buildView(context, viewRoot);
context.getApplication().publishEvent(context, PreRenderViewEvent.class, viewRoot);
vdl.renderView(context, viewRoot);
context.responseComplete();

请注意,如果响应已经提交,则为时已晚。您可能还想事先检查一下。

您可能会找到 source codeOmniFaces FullAjaxExceptionHandler有助于获得一些见解。

关于jsf-2 - 在 JSF 错误处理程序中使用 ExternalContext.dispatch 会导致页面呈现损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15474345/

相关文章:

jsf - primefaces 减少 panelGrid 行之间的间距

date - Primefaces 数据表过滤与日期

jsf-2 - 何时使用 f :view and f:subview

java - 当复合组件放置在 PrimeFaces p :dialog 内时,不会调用 encodeAll 方法

jsf-2 - 单击 <h :panelGroup layout ="block"> 调用支持 bean 操作方法

jsf - 通过复合组件传递 MethodParameter

java - 重复的 JSF 消息

jsf - 使用计时器在JSF托管Bean中生成线程以执行计划的任务

java - JSF 将 <h :outputLabel> text w. r.t 包装到下一行中它自己的起始索引

javascript - 避免关闭模态对话框 bootstrap 和 jsf