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

Jersey 框架統一異常處理機制深度解析與最佳實踐

     編輯:Java 相關知識

為什麼需要統一異常處理?

在成熟 Web 框架下開發業務代碼,只關注 RuntimeException(非受檢異常) 是常態。框架層應封裝 Checked Exception(受檢異常)轉為 Unchecked Exception,業務層拋出自定義業務異常,最後由統一異常映射器轉換為標準 HTTP 響應,實現:

  1. 業務代碼零 try-catch 干擾
  2. 異常信息國際化、標準化
  3. 恰當的 HTTP 狀態碼語義
  4. 完整異常鏈路日誌追蹤

架構分層異常策略

層級異常處理策略示例
框架/基礎設施層捕獲 Checked Exception → 包裝為自定義 Unchecked ExceptionDAO 層 IOException → DaoException
業務邏輯層直接拋出自定義 RuntimeException 子類參數校驗失敗 → ServiceException
接口適配層無業務 try-catch,異常向上拋出Jersey Resource 方法不捕獲異常
統一異常映射層實現 ExceptionMapper<Exception> 統一轉換響應返回 400/404/500 + 國際化錯誤碼

核心代碼實現

1. 異常體系基類

public class BaseException extends RuntimeException {
    private String code;       // 國際化鍵
    private Object[] values;   // 佔位符參數

    public BaseException(String code, Throwable cause, Object[] values) {
        super(code, cause);
        this.code = code;
        this.values = values;
    }
    // getter/setter 省略
}

2. 模塊化業務異常

// DAO 層異常
public class DaoException extends BaseException {
    public DaoException(Throwable cause, String code) {
        super(code, cause, null);
    }
}

// Service 層異常
public class ServiceException extends BaseException {
    public ServiceException(String code) {
        super(code, null, null);
    }
}

3. 國際化錯誤碼配置

# errMsg.properties
read.file.failed=文件讀取失敗
read.config.failed=配置項讀取失敗
must.be.less.than.10=參數必須小於10
request.not.found=請求資源不存在
internal.server.error=服務器內部錯誤

4. 統一異常映射器

@Provider
public class ExceptionMapperSupport implements ExceptionMapper<Exception> {

    @Context HttpServletRequest request;
    @Context ServletContext servletContext;

    private static final Logger LOG = Logger.getLogger(ExceptionMapperSupport.class);

    @Override
    public Response toResponse(Exception ex) {
        String msgKey = "internal.server.error";
        Response.Status status = Response.Status.INTERNAL_SERVER_ERROR;

        // 1. 業務異常:提取 code 國際化
        if (ex instanceof BaseException) {
            BaseException be = (BaseException) ex;
            msgKey = be.getCode();
            // 此處結合 Spring MessageSource 獲取國際化文本
            // String msg = messageSource.getMessage(msgKey, be.getValues(), request.getLocale());
        }
        // 2. Jersey 404
        else if (ex instanceof NotFoundException) {
            msgKey = "request.not.found";
            status = Response.Status.NOT_FOUND;
        }
        // 3. 其他未知異常(含 Checked Exception 泄露)
        // 保持 500,記錄完整堆棧

        // 統一日誌記錄
        LOG.error("異常處理: " + msgKey, ex);

        // 統一響應格式
        return Response.status(status)
                       .entity(msgKey) // 實際項目返回結構化錯誤對象
                       .type(MediaType.TEXT_PLAIN)
                       .build();
    }
}

5. DAO 層轉換示例

@Component
public class TestDao {
    public String sayHello() {
        try (InputStream is = getClass().getResourceAsStream("/test.properties")) {
            Properties props = new Properties();
            props.load(is);
            return props.getProperty("key1") + "," + props.getProperty("key2");
        } catch (IOException e) {
            // Checked Exception → Unchecked Exception
            throw new DaoException(e, "read.file.failed");
        }
    }
}

測試驗證

  • 請求 GET /resources/test?n=11 → 觸發 ServiceException("must.be.less.than.10") → 返回 400 Bad Request + 國際化提示
  • 刪除配置文件 → 觸發 DaoException → 返回 500 Internal Server Error + 日誌含完整堆棧
  • 訪問不存在路徑 → Jersey NotFoundException → 返回 404 Not Found

核心原則總結

  1. 框架層吸收 Checked Exception,業務層只見 Unchecked Exception。
  2. 異常攜帶錯誤碼而非硬編碼文本,支援國際化。
  3. 統一映射器負責:日誌記錄 + HTTP 語義映射 + 響應結構化。
  4. 底層拋出時保留原始異常鏈(new XxxException(e, code)),防止信息丟失。
  5. 非 Web 項目同理:入口處(main、定時任務、MQ 消費者)統一捕獲、記錄、告警、決定是否重試。
異常處理的本質是「失控時的可控性」:讓錯誤可見、可查、可恢復、可度量。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved