首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JSF 與 Struts 全域異常處理機制對比與最佳實踐

     編輯:Java 相關知識

Struts 傳統 BaseAction 模式

在 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 全域異常處理挑戰

JSF 使用 Managed Bean 直接綁定 Action 方法,無中心 Dispatch 點可攔截異常。異常實際從 ActionListenerImpl.processAction() 拋出(MyFaces 實作)。

解決方案:自訂 ActionListener 攔截器

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.propertiesmessage-bundle + FacesMessage
適用版本Struts 1.xJSF 1.1/1.2 (MyFaces/RI)

最佳實踐建議

  1. 定義異常階層:AppException (Checked) 為業務異常基類,SystemException (Runtime) 為系統異常
  2. 統一錯誤碼:業務異常攜帶錯誤碼,前端對應國際化訊息鍵值
  3. 記錄分級:業務異常 DEBUG、系統異常 ERROR + 完整堆疊
  4. 前端顯示:<h:messages globalOnly="true"/> 顯示全域錯誤,<h:message for="componentId"/> 顯示欄位錯誤
  5. 安全考量:生產環境勿暴露堆疊追蹤給使用者,僅記錄日誌

進階:JSF 2.0+ 異常處理

JSF 2.0 引入 <factory> 擴充 ExceptionHandlerFactory,支援更細緻的異常處理生命週期,可替代 ActionListener 方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved