在 BaseAction.execute() 統一捕獲異常:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
try {
String param = mapping.getParameter();
String methodName = processReqCode(request.getParameter(param));
return dispatchMethod(mapping, form, request, response, methodName);
} catch (BaseException ex) { // 業務異常
log.debug("Business error", ex);
return processBaseException(request, mapping, ex);
} catch (Throwable ex) { // 系統異常
log.error("System error", ex);
ActionMessages errors = new ActionMessages();
errors.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage(ex.toString()));
saveErrors(request, errors);
return mapping.findForward("syserror");
}
}
優點:集中處理、區分業務/系統異常、配合 Struts 驗證框架。缺點:侵入性強、所有 Action 必須繼承 BaseAction。
JSF 使用 Managed Bean 直接綁定 Action 方法,無中心 Dispatch 點可攔截異常。異常實際從 ActionListenerImpl.processAction() 拋出(MyFaces 實作)。
public class GlobalActionListener extends ActionListenerImpl {
@Override
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext ctx = FacesContext.getCurrentInstance();
Application app = ctx.getApplication();
ActionSource source = (ActionSource) event.getComponent();
MethodBinding binding = source.getAction();
String fromAction = null;
String outcome = null;
if (binding != null) {
fromAction = binding.getExpressionString();
try {
outcome = (String) binding.invoke(ctx, null); // 執行 Bean Action 方法
} catch (EvaluationException e) {
Throwable cause = e.getCause();
// 攔截自訂業務異常
if (cause != null && cause instanceof AppException) {
FacesUtils.addErrorMessage(
event.getComponent().getClientId(ctx),
cause.getMessage()
);
return; // 不再拋出,讓頁面顯示錯誤訊息
}
throw new AbortProcessingException(cause); // 系統異常繼續拋出
} catch (RuntimeException e) {
throw new FacesException("Action invoke failed: " +
event.getComponent().getClientId(ctx), e);
}
// 正常導航處理
app.getNavigationHandler().handleNavigation(ctx, fromAction, outcome);
ctx.renderResponse();
}
}
}
<!-- faces-config.xml -->
<application>
<action-listener>com.example.GlobalActionListener</action-listener>
<message-bundle>resources.messages</message-bundle>
<locale-config><default-locale>zh_TW</default-locale></locale-config>
</application>
| 維度 | Struts (BaseAction) | JSF (GlobalActionListener) |
|---|---|---|
| 攔截點 | Action.execute() 入口 | ActionListener.processAction() |
| 侵入性 | 需繼承基類 | 零侵入,配置即生效 |
| 業務異常處理 | try-catch 區分型別 | 捕獲 EvaluationException → 判斷 Cause |
| 系統異常處理 | 記錄堆疊 → 全域錯誤頁 | 拋出 AbortProcessingException → 容器處理 |
| 國際化訊息 | ApplicationResources.properties | message-bundle + FacesMessage |
| 適用版本 | Struts 1.x | JSF 1.1/1.2 (MyFaces/RI) |
AppException (Checked) 為業務異常基類,SystemException (Runtime) 為系統異常<h:messages globalOnly="true"/> 顯示全域錯誤,<h:message for="componentId"/> 顯示欄位錯誤JSF 2.0 引入 <factory> 擴充 ExceptionHandlerFactory,支援更細緻的異常處理生命週期,可替代 ActionListener 方案。