Class StandardRestExceptionHandler

java.lang.Object
org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
io.leandev.appfuse.error.StandardRestExceptionHandler
All Implemented Interfaces:
org.springframework.beans.factory.Aware, org.springframework.context.MessageSourceAware

public abstract class StandardRestExceptionHandler extends org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

標準 REST API 異常處理器基類 (RFC 7807)

提供統一的異常處理實作,將所有異常轉換為 RFC 7807 ProblemDetail 格式。 應用層可直接使用或繼承擴展。

繼承 ResponseEntityExceptionHandler 以處理 Spring 框架內建異常。

RFC 7807 錯誤回應格式

{
  "type": "urn:appfuse:error:not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "The requested resource does not exist",
  "instance": "/api/users/123",
  "violations": [...],  // 僅在驗證錯誤時包含
  "format": "...",      // 用於國際化
  "params": [...]       // 訊息參數
}

使用方式

方式 1:直接使用(推薦用於簡單應用)

@ControllerAdvice
public class GlobalRestExceptionHandler extends StandardRestExceptionHandler {
}

方式 2:註冊自定義 Mapper(推薦用於需要自定義異常處理的應用)

@ControllerAdvice
public class GlobalRestExceptionHandler extends StandardRestExceptionHandler {
    static {
        getRegistry().register(new CustomBusinessExceptionMapper());
    }
}
See Also:
  • Field Summary

    Fields inherited from class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

    logger, PAGE_NOT_FOUND_LOG_CATEGORY, pageNotFoundLogger
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    protected
     
    protected
     
  • Method Summary

    Modifier and Type
    Method
    Description
    protected String
    extractPath(org.springframework.web.context.request.WebRequest request)
    從 WebRequest 提取請求路徑
    protected String
    formatViolations(org.springframework.http.ProblemDetail problem)
    將 ProblemDetail 的 violations 渲染成可讀字串,附加於日誌訊息之後
    protected static ExceptionMappingRegistry
    取得異常映射註冊中心 子類別可透過此方法註冊自定義 Mapper
    protected org.springframework.http.ResponseEntity<Object>
    handleAccessDenied(org.springframework.security.access.AccessDeniedException ex, org.springframework.web.context.request.WebRequest request)
    處理授權拒絕(已認證但權限不足)→ 403 Source: Spring Security 方法層授權(@PreAuthorize 等),其拋出的 AuthorizationDeniedExceptionAccessDeniedException 子型別。這類拒絕在 控制器調用期間拋出、先經 MVC 例外解析,若不在此明確映射會落入兜底 handler 被誤判為 500。 此處映為 RFC 7807 的 403 Forbidden。 註:URL 層授權拒絕(authorizeHttpRequests)由 Spring Security filter 的 AccessDeniedHandler 處理、不經此處(亦會帶 RFC 6750 WWW-Authenticate 挑戰標頭)。
    protected org.springframework.http.ResponseEntity<Object>
    handleApplicationException(ApplicationException ex, org.springframework.web.context.request.WebRequest request)
    處理應用程式自定義異常 Source: AppFuse - 業務邏輯層拋出的語義化異常 Includes: NotFoundException, ConflictException, DuplicateException, etc.
    protected org.springframework.http.ResponseEntity<Object>
    handleAuthenticationException(org.springframework.security.core.AuthenticationException ex, org.springframework.web.context.request.WebRequest request)
    處理認證失敗並保留實際 Spring Security 例外至揭露政策邊界。
    protected org.springframework.http.ResponseEntity<Object>
    handleCacheUnavailable(CacheUnavailableException ex, org.springframework.web.context.request.WebRequest request)
    必要的一次性 cache state store 不可用時回 503,不誤映射成無效憑證或 500。
    protected org.springframework.http.ResponseEntity<Object>
    handleFrameworkException(Exception ex, org.springframework.web.context.request.WebRequest request)
    統一處理 Spring 和 Jakarta 框架異常 Sources:
    protected org.springframework.http.ResponseEntity<Object>
    handleHttpClientException(HttpClientException ex, org.springframework.web.context.request.WebRequest request)
    處理 AppFuse HTTP 客戶端異常 Source: AppFuse HTTP Client - HTTP 客戶端呼叫異常
    protected org.springframework.http.ResponseEntity<Object>
    handleJwtException(io.jsonwebtoken.JwtException ex, org.springframework.web.context.request.WebRequest request)
    JWT 驗證錯誤保留原始 parser 診斷;最小政策仍可收斂為 access token 無效。
    protected org.springframework.http.ResponseEntity<Object>
    handleMethodArgumentNotValid(org.springframework.web.bind.MethodArgumentNotValidException ex, org.springframework.http.HttpHeaders headers, org.springframework.http.HttpStatusCode status, org.springframework.web.context.request.WebRequest request)
    處理 @Valid 或 @Validated 驗證失敗 Source: Spring Validation - 當請求體驗證失敗時拋出
    protected org.springframework.http.ResponseEntity<Object>
    handleMissingPathVariable(org.springframework.web.bind.MissingPathVariableException ex, org.springframework.http.HttpHeaders headers, org.springframework.http.HttpStatusCode status, org.springframework.web.context.request.WebRequest request)
    處理路徑變數缺失 Source: Spring Web - 當 @PathVariable 對應的路徑變數缺失時拋出
    protected org.springframework.http.ResponseEntity<Object>
    handleMissingServletRequestParameter(org.springframework.web.bind.MissingServletRequestParameterException ex, org.springframework.http.HttpHeaders headers, org.springframework.http.HttpStatusCode status, org.springframework.web.context.request.WebRequest request)
    處理缺少必要的請求參數 Source: Spring Web - 當 @RequestParam(required=true) 缺失時拋出
    protected org.springframework.http.ResponseEntity<Object>
    handleOtherException(Exception ex, org.springframework.web.context.request.WebRequest request)
    處理所有未捕獲的異常 (兜底處理) Source: 任何未被上述 handler 處理的異常
    protected org.springframework.http.ResponseEntity<Object>
    handleProblemDetail(org.springframework.http.ProblemDetail problem, Throwable cause, org.springframework.web.context.request.WebRequest request)
    統一處理 ProblemDetail 並返回 RFC 7807 格式的 JSON 回應
    protected org.springframework.http.ResponseEntity<Object>
    handleProblemDetail(org.springframework.http.ProblemDetail detailed, org.springframework.http.ProblemDetail minimal, Throwable cause, org.springframework.web.context.request.WebRequest request)
    在所有 mapper 完成後才套用揭露政策,避免上游過早丟棄診斷。
    protected org.springframework.http.ProblemDetail
    將下游 HTTP 回應錯誤映射成對外 ProblemDetail。

    Methods inherited from class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

    createProblemDetail, createResponseEntity, getMessageSource, handleAsyncRequestNotUsableException, handleAsyncRequestTimeoutException, handleConversionNotSupported, handleErrorResponseException, handleException, handleExceptionInternal, handleHandlerMethodValidationException, handleHttpMediaTypeNotAcceptable, handleHttpMediaTypeNotSupported, handleHttpMessageNotReadable, handleHttpMessageNotWritable, handleHttpRequestMethodNotSupported, handleMaxUploadSizeExceededException, handleMethodValidationException, handleMissingServletRequestPart, handleNoHandlerFoundException, handleNoResourceFoundException, handleServletRequestBindingException, handleTypeMismatch, setMessageSource

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • StandardRestExceptionHandler

      protected StandardRestExceptionHandler()
    • StandardRestExceptionHandler

      protected StandardRestExceptionHandler(ErrorDisclosurePolicy disclosurePolicy)
  • Method Details

    • getRegistry

      protected static ExceptionMappingRegistry getRegistry()
      取得異常映射註冊中心 子類別可透過此方法註冊自定義 Mapper
      Returns:
      ExceptionMappingRegistry
    • handleMissingServletRequestParameter

      protected org.springframework.http.ResponseEntity<Object> handleMissingServletRequestParameter(@NonNull org.springframework.web.bind.MissingServletRequestParameterException ex, @NonNull org.springframework.http.HttpHeaders headers, @NonNull org.springframework.http.HttpStatusCode status, @NonNull org.springframework.web.context.request.WebRequest request)
      處理缺少必要的請求參數 Source: Spring Web - 當 @RequestParam(required=true) 缺失時拋出
      Overrides:
      handleMissingServletRequestParameter in class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
    • handleMissingPathVariable

      protected org.springframework.http.ResponseEntity<Object> handleMissingPathVariable(@NonNull org.springframework.web.bind.MissingPathVariableException ex, @NonNull org.springframework.http.HttpHeaders headers, @NonNull org.springframework.http.HttpStatusCode status, @NonNull org.springframework.web.context.request.WebRequest request)
      處理路徑變數缺失 Source: Spring Web - 當 @PathVariable 對應的路徑變數缺失時拋出
      Overrides:
      handleMissingPathVariable in class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
    • handleMethodArgumentNotValid

      protected org.springframework.http.ResponseEntity<Object> handleMethodArgumentNotValid(@NonNull org.springframework.web.bind.MethodArgumentNotValidException ex, @NonNull org.springframework.http.HttpHeaders headers, @NonNull org.springframework.http.HttpStatusCode status, @NonNull org.springframework.web.context.request.WebRequest request)
      處理 @Valid 或 @Validated 驗證失敗 Source: Spring Validation - 當請求體驗證失敗時拋出
      Overrides:
      handleMethodArgumentNotValid in class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
    • handleFrameworkException

      @ExceptionHandler({org.springframework.transaction.TransactionSystemException.class,jakarta.validation.ValidationException.class,org.springframework.dao.DataAccessException.class,org.springframework.http.converter.HttpMessageConversionException.class}) protected org.springframework.http.ResponseEntity<Object> handleFrameworkException(Exception ex, org.springframework.web.context.request.WebRequest request)

      統一處理 Spring 和 Jakarta 框架異常 Sources:

      • TransactionSystemException: Spring Transaction - 事務提交時驗證失敗
      • ValidationException: Jakarta Validation - Bean Validation 驗證失敗
      • DataAccessException: Spring Data - JPA/JDBC 資料庫操作異常
      • HttpMessageConversionException: Spring Web - HTTP 訊息轉換失敗 (如 JSON 解析錯誤)
    • handleHttpClientException

      @ExceptionHandler(HttpClientException.class) protected org.springframework.http.ResponseEntity<Object> handleHttpClientException(HttpClientException ex, org.springframework.web.context.request.WebRequest request)
      處理 AppFuse HTTP 客戶端異常 Source: AppFuse HTTP Client - HTTP 客戶端呼叫異常
    • mapDownstreamHttpException

      protected org.springframework.http.ProblemDetail mapDownstreamHttpException(HttpClientException ex)

      將下游 HTTP 回應錯誤映射成對外 ProblemDetail。

      建立最小揭露政策使用的下游錯誤視圖。下游 401/403 不代表 API caller 未登入或 缺少本服務權限,因此收斂為 502;其他狀態碼維持既有對外狀態。最大揭露政策則 使用保留服務、原始狀態、路徑與錯誤內容的詳細視圖。特殊整合可覆寫此方法,自訂 應用層最小揭露契約。

      Parameters:
      ex - 帶下游來源脈絡的 HTTP client 例外
      Returns:
      對外 ProblemDetail
    • handleApplicationException

      @ExceptionHandler(ApplicationException.class) protected org.springframework.http.ResponseEntity<Object> handleApplicationException(ApplicationException ex, org.springframework.web.context.request.WebRequest request)
      處理應用程式自定義異常 Source: AppFuse - 業務邏輯層拋出的語義化異常 Includes: NotFoundException, ConflictException, DuplicateException, etc.
    • handleCacheUnavailable

      @ExceptionHandler(CacheUnavailableException.class) protected org.springframework.http.ResponseEntity<Object> handleCacheUnavailable(CacheUnavailableException ex, org.springframework.web.context.request.WebRequest request)
      必要的一次性 cache state store 不可用時回 503,不誤映射成無效憑證或 500。
    • handleAccessDenied

      @ExceptionHandler(org.springframework.security.access.AccessDeniedException.class) protected org.springframework.http.ResponseEntity<Object> handleAccessDenied(org.springframework.security.access.AccessDeniedException ex, org.springframework.web.context.request.WebRequest request)
      處理授權拒絕(已認證但權限不足)→ 403 Source: Spring Security 方法層授權(@PreAuthorize 等),其拋出的 AuthorizationDeniedExceptionAccessDeniedException 子型別。這類拒絕在 控制器調用期間拋出、先經 MVC 例外解析,若不在此明確映射會落入兜底 handler 被誤判為 500。 此處映為 RFC 7807 的 403 Forbidden。 註:URL 層授權拒絕(authorizeHttpRequests)由 Spring Security filter 的 AccessDeniedHandler 處理、不經此處(亦會帶 RFC 6750 WWW-Authenticate 挑戰標頭)。
    • handleAuthenticationException

      @ExceptionHandler(org.springframework.security.core.AuthenticationException.class) protected org.springframework.http.ResponseEntity<Object> handleAuthenticationException(org.springframework.security.core.AuthenticationException ex, org.springframework.web.context.request.WebRequest request)
      處理認證失敗並保留實際 Spring Security 例外至揭露政策邊界。
    • handleJwtException

      @ExceptionHandler(io.jsonwebtoken.JwtException.class) protected org.springframework.http.ResponseEntity<Object> handleJwtException(io.jsonwebtoken.JwtException ex, org.springframework.web.context.request.WebRequest request)
      JWT 驗證錯誤保留原始 parser 診斷;最小政策仍可收斂為 access token 無效。
    • handleOtherException

      @ExceptionHandler(Exception.class) protected org.springframework.http.ResponseEntity<Object> handleOtherException(Exception ex, org.springframework.web.context.request.WebRequest request)
      處理所有未捕獲的異常 (兜底處理) Source: 任何未被上述 handler 處理的異常
    • handleProblemDetail

      protected org.springframework.http.ResponseEntity<Object> handleProblemDetail(org.springframework.http.ProblemDetail problem, Throwable cause, org.springframework.web.context.request.WebRequest request)
      統一處理 ProblemDetail 並返回 RFC 7807 格式的 JSON 回應
      Parameters:
      problem - ProblemDetail 物件
      cause - 原始異常(用於日誌記錄)
      request - WebRequest(用於取得請求路徑)
    • handleProblemDetail

      protected org.springframework.http.ResponseEntity<Object> handleProblemDetail(org.springframework.http.ProblemDetail detailed, org.springframework.http.ProblemDetail minimal, Throwable cause, org.springframework.web.context.request.WebRequest request)
      在所有 mapper 完成後才套用揭露政策,避免上游過早丟棄診斷。
    • formatViolations

      protected String formatViolations(org.springframework.http.ProblemDetail problem)

      將 ProblemDetail 的 violations 渲染成可讀字串,附加於日誌訊息之後

      Bean Validation 的違規訊息是通用句(每個欄位皆為 "must not be blank"), 欄位名只存在於 Violation.getProps()。日誌若僅記錄 detail,違規欄位就完全遺失。

      Parameters:
      problem - ProblemDetail 物件
      Returns:
      形如 violations=[email=must not be blank];無違規時回空字串
    • extractPath

      protected String extractPath(org.springframework.web.context.request.WebRequest request)
      從 WebRequest 提取請求路徑