我正在Glassfish v3上开发一个JSF 2.0应用程序,我正在尝试处理ViewExpiredException。但无论我做什么,我总是得到一个Glassfish错误报告而不是我自己的错误页面。
为了模拟VEE的发生,我将以下函数插入到我的支持bean中,它会激活VEE。我通过commandLink从我的JSF页面触发此函数。 守则:
@Named
public class PersonHome {
(...)
public void throwVEE() {
throw new ViewExpiredException();
}
}
起初我只是通过向我的web.xml添加错误页面来尝试它:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/error.xhtml</location>
</error-page>
但是这不起作用,我没有被重定向到错误但是我显示了Glassfish errorpage,它显示了一个HTTP Status 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
我尝试的下一件事是编写ExceptionHandlerFactory和CustomExceptionHandler,如 JavaServerFaces 2.0 - 完整参考中所述。所以我将以下标记插入faces-config.xml:
<factory>
<exception-handler-factory>
exceptions.ExceptionHandlerFactory
</exception-handler-factory>
</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错误。 我做错了什么,在我的实现中可能缺少哪些异常未正确处理? 任何帮助高度赞赏!
修改
好的,我老实说。事实上,我的代码实际上是用Scala编写的,但这是一个很长的故事。我一直认为这是一个Java问题。 在这种情况下,真正的错误是我自己的愚蠢。在我的(Scala)代码中,在CustomExceptionHandler中,我忘了添加带有“i.remove();”的行。所以ViewExpiredException在处理完之后仍留在UnhandledExceptionsQueue中,并且“冒泡”。 当它冒泡时,它就变成了ServletException。
我真的很抱歉让你们两个都感到困惑!
答案 0 :(得分:14)
这个测试用例是假的。 ViewExpiredException
通常仅在恢复视图期间抛出(因为它在会话中丢失),而不是在渲染响应期间或实例化bean时。在您的情况下,在实例化bean期间抛出此异常,并且此异常包含在ServletException
中。
真实 ViewExpiredException
通常仅在HTTP会话过期时向服务器发送HTTP POST请求时抛出。因此,基本上有两种方法可靠地重现这一点:
在Web浏览器中打开一个带有POST表单(h:form
默认已经是POST)的JSF页面,关闭服务器并清理其工作目录(这很重要,因为大多数服务器会将打开的会话序列化为磁盘在关闭并在启动时反序列化它们,重新启动服务器并提交已打开的表单。 <{1}}将被抛出。
将ViewExpiredException
中的<session-timeout>
设置为web.xml
分钟,并在打开带有POST表单的JSF页面后1分钟内提交表单。这也将抛出1
。
答案 1 :(得分:2)
我不是专家。这些只是猜测或建议。
1)尝试重定向到标准HTML页面以查看是否有效 2)Based on this,它应该与第一种方法本身一起使用,尝试编写JSF PhaseListener并在RESTORE VIEW阶段抛出相同的异常。现在,你要么投入INVOKE APPLICATION或UPDATE MODEL阶段。 3)通过sysout,确保配置了错误页面 - 使用Servlet Context(我没有尝试过,但应该可以)
即使我很好奇可能是什么问题!!! !!!