JSF:无法捕获 ViewExpiredException [英] JSF: Cannot catch ViewExpiredException

查看:26
本文介绍了JSF:无法捕获 ViewExpiredException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 Glassfish v3 上开发 JSF 2.0 应用程序,我正在尝试处理 ViewExpiredException.但无论我做什么,我总是收到 Glassfish 错误报告而不是我自己的错误页面.

I'm developing a JSF 2.0 application on Glassfish v3 and i'm trying to handle the ViewExpiredException. But whatever i do, i always get a Glassfish error report instead of my own error page.

为了模拟 VEE 的发生,我将以下函数插入到我的支持 bean 中,它会触发 VEE.我正在通过 commandLink 从我的 JSF 页面触发此功能.代码:

To simulate the occurrence of the VEE, i inserted the following function into my backing bean, which fires the VEE. I'm triggering this function from my JSF page through a commandLink. The Code:

@Named
public class PersonHome {
  (...)
  public void throwVEE() {
    throw new ViewExpiredException();
  }
}

起初我通过简单地向我的 web.xml 添加一个错误页面来尝试它:

At first i tried it by simply adding an error-page to my web.xml:

<error-page>
  <exception-type>javax.faces.application.ViewExpiredException</exception-type>
  <location>/error.xhtml</location>
</error-page>  

但这不起作用,我没有被重定向到错误,但我看到了 Glassfish 错误页面,它显示了一个 HTTP 状态 500 页面,内容如下:

But this doesn't work, i'm not redirected to error but i'm shown the Glassfish errorpage, which shows a HTTP Status 500 page with the following content:

description:The server encountered an internal error () that prevented it from fulfilling this request.
exception: javax.servlet.ServletException: javax.faces.application.ViewExpiredException
root cause: javax.faces.el.EvaluationException:javax.faces.application.ViewExpiredException
root cause:javax.faces.application.ViewExpiredException

接下来我尝试编写 ExceptionHandlerFactory 和 CustomExceptionHandler,如JavaServerFaces 2.0 - 完整参考中所述.所以我将以下标签插入到 faces-config.xml 中:

Next thing i tried was to write ExceptionHandlerFactory and a CustomExceptionHandler, as described in JavaServerFaces 2.0 - The Complete Reference. So i inserted the following tag into faces-config.xml:

<factory>
  <exception-handler-factory>
    exceptions.ExceptionHandlerFactory
  </exception-handler-factory>
</factory>

并添加了这些类:工厂:

And added these classes: The factory:

package exceptions;

import javax.faces.context.ExceptionHandler;

public class ExceptionHandlerFactory extends javax.faces.context.ExceptionHandlerFactory {

    private javax.faces.context.ExceptionHandlerFactory parent;

    public ExceptionHandlerFactory(javax.faces.context.ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        ExceptionHandler result = parent.getExceptionHandler();
        result = new CustomExceptionHandler(result);
        return result;
    }

}

自定义异常处理程序:

package exceptions;

import java.util.Iterator;

import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

class CustomExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler parent;

    public CustomExceptionHandler(ExceptionHandler parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.parent;
    }

    @Override
    public void handle() throws FacesException {
        for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            System.out.println("Iterating over ExceptionQueuedEvents. Current:" + event.toString());
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            Throwable t = context.getException();
            if (t instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) t;
                FacesContext fc = FacesContext.getCurrentInstance();

                NavigationHandler nav =
                        fc.getApplication().getNavigationHandler();
                try {
                    // Push some useful stuff to the flash scope for
                    // use in the page
                    fc.getExternalContext().getFlash().put("expiredViewId", vee.getViewId());

                    nav.handleNavigation(fc, null, "/login?faces-redirect=true");
                    fc.renderResponse();

                } finally {
                    i.remove();
                }
            }
        }
        // At this point, the queue will not contain any ViewExpiredEvents.
        // Therefore, let the parent handle them.
        getWrapped().handle();
    }
}

但是我仍然没有被重定向到我的错误页面 - 我收到了与上面相同的 HTTP 500 错误.我做错了什么,我的实现中可能缺少什么异常处理不正确?任何帮助非常感谢!

But STILL i'm NOT redirected to my error page - i'm getting the same HTTP 500 error like above. What am i doing wrong, what could be missing in my implementation that the exception isn't handled correctly? Any help highly appreciated!

编辑

好吧,我是诚实的.事实上,我的代码实际上是用 Scala 编写的,但那是一个很长的故事.我一直认为这是一个Java问题.在这种情况下真正的错误是我自己的愚蠢.在我的 (Scala) 代码中,在 CustomExceptionHandler 中,我忘记添加带有i.remove();"的行所以 ViewExpiredException 在处理完之后留在 UnhandledExceptionsQueue 中,并且冒泡"了.当它冒泡时,它变成了一个 ServletException.

Ok, i'm honest. In fact, my code is actually written in Scala, but thats a long story. i thought it was a Java problem all the time. The REAL error in this case was my own stupidness. In my (Scala) code, in CustomExceptionHandler, i forgot to add the line with the "i.remove();" So the ViewExpiredException stayed in the UnhandledExceptionsQueue after handling it, and it "bubbled up". And when it bubbles up, it becomes a ServletException.

我真的很抱歉让你们俩混淆了!

I'm really sorry for confusing you both!

推荐答案

这个测试用例是假的.ViewExpiredException 通常只在恢复视图期间抛出(因为它在会话中丢失),而不是在呈现响应或实例化 bean 期间.在您的情况下,此异常是在实例化 bean 期间引发的,并且此异常被包装在 ServletException 中.

This test case is bogus. The ViewExpiredException is usually only thrown during restoring the view (because it's missing in the session), not during rendering the response nor instantiating the bean. In your case this exception is thrown during instantiating the bean and this exception is been wrapped in a ServletException.

real ViewExpiredException 通常只有在 HTTP 会话过期的情况下向服务器发送 HTTP POST 请求时才会抛出.所以基本上有两种方法可以可靠地重现这一点:

The real ViewExpiredException is usually only thrown when you send a HTTP POST request to the server while the HTTP session is expired. So there are basically two ways to reproduce this reliably:

  1. 在浏览器中打开一个带有 POST 表单(h:form 默认已经是 POST)的 JSF 页面,关闭服务器并清理它的工作目录(很重要,因为大多数服务器都会在关闭时将打开的会话序列化到磁盘并在启动时将它们反序列化),重新启动服务器并提交已经打开的表单.将抛出 ViewExpiredException.

  1. Open a JSF page with a POST form (h:form is by default already POST) in a webbrowser, shutdown the server and clean its work directory (important, because most servers will serialize open sessions to disk on shutdown and unserialize them on startup), restart the server and submit the already opened form. A ViewExpiredException will be thrown.

web.xml中的设置为1分钟,1分钟后提交表单使用 POST 表单打开 JSF 页面.这也会抛出 ViewExpiredException .

Set the <session-timeout> in web.xml to 1 minute and submit the form over 1 minute after opening the JSF page with the POST form. This will throw the ViewExpiredException as well.

这篇关于JSF:无法捕获 ViewExpiredException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆