问题描述
我正在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的发生,我将以下函数插入到我的支持中发射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 errorpage,显示带有以下内容的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:
-
打开一个带有POST表单的JSF页面( h:form 默认情况下已经是POST),关闭服务器并清理其工作目录(这很重要,因为大多数服务器会在关机时将打开的会话序列化为磁盘并在启动时将它们反序列化),重新启动服务器并提交已打开的表单。将抛出
ViewExpiredException
。
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. AViewExpiredException
will be thrown.
设置< session-timeout> ;
在 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!