JSF 处理 Ajax 事件中的异常
JSF Handle Exception in Ajax events
我遵循了这个 solution 并在 ViewExpiredException 发生时完美地工作,但是当我检查(firefox 实用程序)视图错误时,我看到它替换它,但就在正常的 body 标签内视图,我的意思是,导致异常的视图。视图错误在他自己的 body 标签中声明了 css class,但我不知道,为什么不替换整个视图错误,而是只获取所有内容(在他的 body 标签之后) 的视图错误并插入普通视图的 body 标记内?
为了得到这个行为,我有一个登录视图(我在上面提到的普通视图)并且只需要等到会话过期,然后我尝试登录(提交视图的表单)并且这会触发一个异常处理程序渲染视图错误。
这里有一些片段:
login.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
</f:facet>
<title>PrimeFaces</title>
</h:head>
<h:body styleClass="login-body">
<div class="login-panel ui-fluid">
<div class="ui-g">
<div class="ui-g-12 logo-container">
<p:graphicImage name="images/logo-colored.png" library="theme-layout" />
<h1>Login to Your Account</h1>
<h2>WELCOME</h2>
</div>
<div class="ui-g-12">
<p:inputText placeholder="User" />
</div>
<div class="ui-g-12">
<p:password placeholder="Password" feedback="false"/>
</div>
<div class="ui-g-12 chkbox-container">
<p:selectBooleanCheckbox id="remember-me" />
<p:outputLabel for="remember-me" value="Remember Me"/>
</div>
<div class="ui-g-12 button-container">
<p:commandButton type="submit" value="Log in" icon="fa fa-user" styleClass="orange-btn" action="#{menu.login}" update="frmLoginPromo">
</div>
</div>
</div>
<h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="theme-layout" />
</h:body>
</html>
error.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
</f:facet>
<title>PrimeFaces - Error </title>
</h:head>
<h:body styleClass="exception-body">
<div class="exception-panel">
<p:graphicImage name="images/icon-error.png" library="theme-layout" />
<h1>Error Occured</h1>
<p>An error occured, please try again later.</p>
</div>
<h:outputStylesheet name="css/layout-blue.css" library="theme-layout" />
</h:body>
</html>
CustomExceptionHandler.java
@Override
public void handle() throws FacesException{
final Iterator<ExceptionQueuedEvent> lclExceptionQueue = getUnhandledExceptionQueuedEvents().iterator();
final FacesContext lclFacesContext = FacesContext.getCurrentInstance();
final Map<String, Object> requestMap = lclFacesContext.getExternalContext().getSessionMap();
while (lclExceptionQueue.hasNext()){
ExceptionQueuedEvent event = lclExceptionQueue.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable lclThrowable = context.getException();
try{
if (lclThrowable instanceof ViewExpiredException){
lclFacesContext.setViewRoot(lclFacesContext.getApplication().getViewHandler().createView(lclFacesContext, "/error.xhtml"));
lclFacesContext.getPartialViewContext().setRenderAll(true);
lclFacesContext.renderResponse();
}
}finally{
lclExceptionQueue.remove();
}
}
getWrapped().handle();
}
错误视图呈现后的样子
Inspecte view error
请告诉我哪里做错了?
既然您已经在使用 PrimeFaces,我会选择不开发您自己的异常处理程序。 PrimeFaces already has one that can handle both ajax and non-ajax requests。
对于不使用 PrimeFaces 的人,我建议使用 OmniFaces exceptionhandling
对于 PrimeFaces 6.2 the documentation 包含在第 11.3 章中进行配置的信息(顺便说一句,这与 PF 6.1 的章节相同)
总结(所有引用均来自 PF 文档)
配置 el 解析器和异常处理程序
<application>
<el-resolver>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver
</el-resolver>
</application>
<factory>
<exception-handler-factory>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory
</exception-handler-factory>
</factory>
如果您想在 web.xml
中配置错误页面
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/ui/error/error.jsf</location>
</error-page>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/ui/error/viewExpired.jsf</location>
</error-page>
然后您可以在错误页面中使用有关 EL 异常的信息
<h:outputText value="Message:#{pfExceptionHandler.message}" />
<h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" />
有更多信息,我建议查阅文档。
对于 ajax 你可以做的例外情况
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException"
update="exceptionDialog" onexception="PF('exceptionDialog').show();" />
<p:dialog id="exceptionDialog" header="Exception: #{pfExceptionHandler.type}
occured!" widgetVar="exceptionDialog" height="500px">
Message: #{pfExceptionHandler.message} <br/>
StackTrace: <h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" />
<p:button onclick="document.location.href = document.location.href;"
value="Reload!"/>
</p:dialog>
OmniFaces 的配置非常相似。
另请参阅:
- Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request
我遵循了这个 solution 并在 ViewExpiredException 发生时完美地工作,但是当我检查(firefox 实用程序)视图错误时,我看到它替换它,但就在正常的 body 标签内视图,我的意思是,导致异常的视图。视图错误在他自己的 body 标签中声明了 css class,但我不知道,为什么不替换整个视图错误,而是只获取所有内容(在他的 body 标签之后) 的视图错误并插入普通视图的 body 标记内?
为了得到这个行为,我有一个登录视图(我在上面提到的普通视图)并且只需要等到会话过期,然后我尝试登录(提交视图的表单)并且这会触发一个异常处理程序渲染视图错误。
这里有一些片段:
login.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
</f:facet>
<title>PrimeFaces</title>
</h:head>
<h:body styleClass="login-body">
<div class="login-panel ui-fluid">
<div class="ui-g">
<div class="ui-g-12 logo-container">
<p:graphicImage name="images/logo-colored.png" library="theme-layout" />
<h1>Login to Your Account</h1>
<h2>WELCOME</h2>
</div>
<div class="ui-g-12">
<p:inputText placeholder="User" />
</div>
<div class="ui-g-12">
<p:password placeholder="Password" feedback="false"/>
</div>
<div class="ui-g-12 chkbox-container">
<p:selectBooleanCheckbox id="remember-me" />
<p:outputLabel for="remember-me" value="Remember Me"/>
</div>
<div class="ui-g-12 button-container">
<p:commandButton type="submit" value="Log in" icon="fa fa-user" styleClass="orange-btn" action="#{menu.login}" update="frmLoginPromo">
</div>
</div>
</div>
<h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="theme-layout" />
</h:body>
</html>
error.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
</f:facet>
<title>PrimeFaces - Error </title>
</h:head>
<h:body styleClass="exception-body">
<div class="exception-panel">
<p:graphicImage name="images/icon-error.png" library="theme-layout" />
<h1>Error Occured</h1>
<p>An error occured, please try again later.</p>
</div>
<h:outputStylesheet name="css/layout-blue.css" library="theme-layout" />
</h:body>
</html>
CustomExceptionHandler.java
@Override
public void handle() throws FacesException{
final Iterator<ExceptionQueuedEvent> lclExceptionQueue = getUnhandledExceptionQueuedEvents().iterator();
final FacesContext lclFacesContext = FacesContext.getCurrentInstance();
final Map<String, Object> requestMap = lclFacesContext.getExternalContext().getSessionMap();
while (lclExceptionQueue.hasNext()){
ExceptionQueuedEvent event = lclExceptionQueue.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable lclThrowable = context.getException();
try{
if (lclThrowable instanceof ViewExpiredException){
lclFacesContext.setViewRoot(lclFacesContext.getApplication().getViewHandler().createView(lclFacesContext, "/error.xhtml"));
lclFacesContext.getPartialViewContext().setRenderAll(true);
lclFacesContext.renderResponse();
}
}finally{
lclExceptionQueue.remove();
}
}
getWrapped().handle();
}
错误视图呈现后的样子
Inspecte view error 请告诉我哪里做错了?
既然您已经在使用 PrimeFaces,我会选择不开发您自己的异常处理程序。 PrimeFaces already has one that can handle both ajax and non-ajax requests。
对于不使用 PrimeFaces 的人,我建议使用 OmniFaces exceptionhandling
对于 PrimeFaces 6.2 the documentation 包含在第 11.3 章中进行配置的信息(顺便说一句,这与 PF 6.1 的章节相同)
总结(所有引用均来自 PF 文档)
配置 el 解析器和异常处理程序
<application> <el-resolver> org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver </el-resolver> </application> <factory> <exception-handler-factory> org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory </exception-handler-factory> </factory>
如果您想在 web.xml
中配置错误页面<error-page> <exception-type>java.lang.Throwable</exception-type> <location>/ui/error/error.jsf</location> </error-page> <error-page> <exception-type>javax.faces.application.ViewExpiredException</exception-type> <location>/ui/error/viewExpired.jsf</location> </error-page>
然后您可以在错误页面中使用有关 EL 异常的信息
<h:outputText value="Message:#{pfExceptionHandler.message}" /> <h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" />
有更多信息,我建议查阅文档。
对于 ajax 你可以做的例外情况
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException" update="exceptionDialog" onexception="PF('exceptionDialog').show();" /> <p:dialog id="exceptionDialog" header="Exception: #{pfExceptionHandler.type} occured!" widgetVar="exceptionDialog" height="500px"> Message: #{pfExceptionHandler.message} <br/> StackTrace: <h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" /> <p:button onclick="document.location.href = document.location.href;" value="Reload!"/> </p:dialog>
OmniFaces 的配置非常相似。
另请参阅:
- Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request