【问题标题】:Bug report form on error page错误页面上的错误报告表
【发布时间】:2012-10-31 22:49:10
【问题描述】:

我在 JBoss 7.1 和 Richfaces 4.1 中有一个 JSF Web 应用程序。我尝试在 web.xml 中配置自定义错误页面,但遇到了问题,这不适用于 AJAX 请求。作为解决方案,我尝试使用Omnifaces FullAjaxExceptionHandler,它可以很好地显示错误页面。

但是,我想添加一个表单,允许用户输入其他信息并将其与例外一起作为电子邮件发送给我。问题是在错误页面上,提交按钮不起作用。当我单击它时,错误页面刚刚重新加载。在下一次点击时,一切都按预期工作。

错误页面模板中的小菜单中的 h:commandlinks 也会出现同样的问题。

我对 JSF 很陌生,所以我真的不知道为什么会发生这种情况以及如何解决它。或者有没有更好的方法来做到这一点?

【问题讨论】:

    标签: ajax jsf exception-handling omnifaces


    【解决方案1】:

    这与 JSF spec issue 790 相关,归结为 ajax 更新某些组件,而该组件又包含一个或多个 <h:form> 组件,无法正确更新这些表单的新视图状态标识符。

    这个问题在即将发布的 JSF 2.2 中得到修复,但在此之前,您必须使用以下基于 JavaScript 的解决方法。

    jsf.ajax.addOnEvent(function(data) {
        if (data.status == "success") {
            var viewState = getViewState(data.responseXML);
    
            if (viewState) {
                for (var i = 0; i < document.forms.length; i++) {
                    var form = document.forms[i];
    
                    if (!hasViewState(form)) {
                        createViewState(form, viewState);
                    }
                }
            }
        }
    });
    
    function getViewState(responseXML) {
        var updates = responseXML.getElementsByTagName("update");
    
        for (var i = 0; i < updates.length; i++) {
            var update = updates[i];
    
            if (update.getAttribute("id") == "javax.faces.ViewState") {
                return update.firstChild.nodeValue;
            }
        }
    
        return null;
    }
    
    function hasViewState(form) {
        for (var i = 0; i < form.elements.length; i++) {
            if (form.elements[i].name == "javax.faces.ViewState") {
                return true;
            }
        }
    
        return false;
    }
    
    function createViewState(form, viewState) {
        var hidden;
    
        try {
            hidden = document.createElement("<input name='javax.faces.ViewState'>"); // IE6-8.
        } catch(e) {
            hidden = document.createElement("input");
            hidden.setAttribute("name", "javax.faces.ViewState");
        }
    
        hidden.setAttribute("type", "hidden");
        hidden.setAttribute("value", viewState);
        hidden.setAttribute("autocomplete", "off");
        form.appendChild(hidden);
    }
    

    只需将其作为&lt;h:outputScript name="some.js" target="head"&gt; 包含在错误页面的&lt;h:body&gt; 中即可。如果您不能保证页面使用 JSF &lt;f:ajax&gt;,那么您可能需要在 jsf.ajax.addOnEvent() 调用之前添加一个额外的 if (typeof jsf !== 'undefined') 检查。

    JSF 组件库 PrimeFaces 已经在其核心 ajax 引擎中解决了这个问题,所以如果你碰巧已经使用它,你可能想用 PrimeFaces 替换所有 &lt;f:ajax&gt; 链接/按钮。

    另见:

    【讨论】:

    • 感谢您的快速答复。奇怪的是,错误页面在通过异常处理程序呈现时不包含 javax.faces.ViewState 元素。所以 document.getElementsByName("javax.faces.ViewState") 什么也没找到。该元素存在于上一页(已引发异常)并且如果我手动打开错误页面。如果这有什么不同,我正在使用 Richfaces a4j:commandbutton。
    • 哦,对了,如果使用 @all 渲染而不是部分渲染,这有点傻,我在答案中修复了示例。
    • 这很好。因此 data.responseXML 包含来自异常处理程序的 ajax 响应。好的,再次感谢。这真的很有帮助。
    • 这似乎不适用于 Firefox,因为 getElementById() 仅当属性在 DTD 中指定为 ID 时才有效。我现在使用了一些 getElementsByName("update") 并遍历它们以检查正确的 id。
    猜你喜欢
    • 2016-11-26
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 2013-10-05
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多