在struts中通常采用的全局错误控制模式是构建一个baseAction在其execute方法中完成前台传回方法的dispatch操作并由 try……catch……捕获程序错误实现错误的控制和展示一个典型的BaseAction例子如下
代码
public ActionForward execute(ActionMapping mapping ActionForm form HttpServletRequest request HttpServletResponse response) {
……
ActionForward forwardPage = null
try {
String parameter = mappinggetParameter()
if (parameter == null) {
String message = messagesgetMessage(dispatchhandler mappinggetPath())
responsesendError( message)
return null
}
String name = processReqCode(requestgetParameter(parameter))
forwardPage = dispatchMethod(mapping form request response name)
} catch (BaseException ex) {
if (logisDebugEnabled())
logdebug(发生错误 ex)
forwardPage = processBaseException(request mapping ex)
} catch (Throwable ex) {
logerror(发生错误 ex)
ActionMessages errors = new ActionMessages()
ByteArrayOutputStream ostr = new ByteArrayOutputStream()
exprintStackTrace(new PrintStream(ostr))
errorsadd(orgapachestrutsactionGLOBAL_MESSAGE new ActionMessage(ostrtoString()))
saveErrors(request errors)
forwardPage = mappingfindForward(syserror)
outputsetStatus(fail)
outputsetError(exgetMessage())
}
……
}
由于JSF采用了managed beanJSP页面直接通过调用managed bean中的方法完成数据交互不能像struts一样通过捕获dispatch操作过程抛出的异常来完成错误的处理(因为根本就没有dispatch方法)似乎jsf根本就不支持全局的错误处理
如果在managed bean中throw 一个exception(这里是AppException)观察一下控制台的日志可以看到其实错误是从一个ActionListener的实现中抛出的(针对myfaces这里是ActionListenerImpl)参考jsf的生命周期过程方法出来了
代码
public class GlobalActionListener extends ActionListenerImpl {
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext facesContext = FacesContextgetCurrentInstance()
Application application = facesContextgetApplication()
ActionSource actionSource = (ActionSource) eventgetComponent()
MethodBinding methodBinding = actionSourcegetAction()
String fromAction = nullString outcome = null
if (methodBinding != null) {
fromAction = methodBindinggetExpressionString()
try {
outcome = (String) methodBindinginvoke(facesContext null)
} catch (EvaluationException e) {
Throwable cause = egetCause()
if (cause != null && cause instanceof AppException) {
//这里需要根据框架的不同判断实例是否是程序中手动抛出的错误
FacesUtilsaddErrorMessage(eventgetComponent()getClientId(facesContext)causegetMessage())}
else {
throw (AbortProcessingException) cause
}
} catch (RuntimeException e) {
throw new FacesException(Error calling action method of component with id + eventgetComponent()getClientId(facesContext) e)
}
NavigationHandler navigationHandler = applicationgetNavigationHandler()
navigationHandlerhandleNavigation(facesContext fromAction outcome)
// Render Response if needed
facesContextrenderResponse()
}
}
监听器配置facesconfigapplicationxml
代码
<application>
<variableresolver>orgspringframeworkwebjsfDelegatingVariableResolver</variableresolver>
<messagebundle>resourcesapplication</messagebundle>
<localeconfig>
<defaultlocale>en</defaultlocale>
</localeconfig>
<actionlistener>orgsnailportalwebframeworklistenerGlobalActionListener</actionlistener>
</application>
这样开发人员只需要在action和managed bean里面根据业务的需要抛出指定基础类型的Exception实例由BaseAction和ActionListener完成错误的封装处理再传递给前台进行显示从而减少开发的代码量提高框架的可维护性