java JSF:无法捕获 ViewExpiredException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2980708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSF: Cannot catch ViewExpiredException
提问by Ingo Fischer
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.
我正在 Glassfish v3 上开发 JSF 2.0 应用程序,我正在尝试处理 ViewExpiredException。但无论我做什么,我总是得到 Glassfish 错误报告而不是我自己的错误页面。
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:
为了模拟 VEE 的发生,我将以下函数插入到我的支持 bean 中,它会触发 VEE。我正在通过 commandLink 从我的 JSF 页面触发此功能。代码:
@Named
public class PersonHome {
(...)
public void throwVEE() {
throw new ViewExpiredException();
}
}
At first i tried it by simply adding an error-page to my web.xml:
起初我通过简单地向我的 web.xml 添加一个错误页面来尝试它:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/error.xhtml</location>
</error-page>
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:
但这不起作用,我没有被重定向到错误,但我看到了 Glassfish 错误页面,它显示了一个 HTTP 状态 500 页面,其中包含以下内容:
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
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:
接下来我尝试编写 ExceptionHandlerFactory 和 CustomExceptionHandler,如JavaServerFaces 2.0 - The Complete Reference 中所述。所以我将以下标签插入到 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;
}
}
The custom exception handler:
自定义异常处理程序:
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();
}
}
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? Anyhelp highly appreciated!
但是我仍然没有被重定向到我的错误页面 - 我收到了与上面相同的 HTTP 500 错误。我做错了什么,我的实现中可能缺少什么异常处理不正确?任何帮助高度赞赏!
EDIT
编辑
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.
好吧,我是诚实的。事实上,我的代码实际上是用 Scala 编写的,但那是一个很长的故事。我一直认为这是一个Java问题。在这种情况下真正的错误是我自己的愚蠢。在我的 (Scala) 代码中,在 CustomExceptionHandler 中,我忘记添加带有“i.remove();”的行 所以 ViewExpiredException 在处理完之后留在 UnhandledExceptionsQueue 中,并且“冒泡”了。当它冒泡时,它变成了一个 ServletException。
I'm really sorry for confusing you both!
给你们造成困扰真的很抱歉!
回答by BalusC
This test case is bogus. The ViewExpiredExceptionis 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.
这个测试用例是假的。在ViewExpiredException通常恢复视图(因为它缺少在会议)期间,未呈现响应,也没有实例化的bean时只被扔出。在您的情况下,此异常是在实例化 bean 期间引发的,并且此异常被包装在ServletException.
The realViewExpiredExceptionis 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:
在真正ViewExpiredException当您在HTTP会话过期发送一个HTTP POST请求到服务器通常只抛出。所以基本上有两种方法可以可靠地重现这一点:
Open a JSF page with a POST form (
h:formis 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. AViewExpiredExceptionwill be thrown.Set the
<session-timeout>inweb.xmlto1minute and submit the form over 1 minute after opening the JSF page with the POST form. This will throw theViewExpiredExceptionas well.
h:form在浏览器中打开一个带有 POST 表单(默认情况下已经是 POST)的 JSF 页面,关闭服务器并清理它的工作目录(很重要,因为大多数服务器会在关闭时将打开的会话序列化到磁盘并在启动时将它们反序列化),重新启动服务器并提交已经打开的表单。AViewExpiredException将被抛出。将
<session-timeout>in设置web.xml为1minute,在用POST表单打开JSF页面后1分钟内提交表单。这也会抛出ViewExpiredException。
回答by gekrish
I am not an expert. These are just wild guesses or suggestions.
我不是专家。这些只是疯狂的猜测或建议。
1) Try redirecting to a standard HTML page to see if that works 2) Based on this, it should work with the first approach itself, try writing a JSF PhaseListener and throw the same exception in the RESTORE VIEW Phase.Right now, you are throwing either in the INVOKE APPLICATION or UPDATE MODEL Phase. 3) By a sysout , make sure that the error page is configured - using Servlet Context (I have not tried this but It should be possible)
1) 尝试重定向到标准 HTML 页面以查看是否有效 2)基于此,它应该与第一种方法本身一起使用,尝试编写 JSF PhaseListener 并在 RESTORE VIEW 阶段抛出相同的异常。现在,您是在调用应用程序或更新模型阶段抛出。3)通过 sysout ,确保配置了错误页面 - 使用 Servlet Context(我没有尝试过这个,但应该是可能的)
Even I am curious what could be the problem is!!!
即使我很好奇可能是什么问题!!!

