在開發 Spring Boot 時,當我們丟出一個 exception,Spring Boot 的 exception handler 會幫我們處理它,並且傳回一個 JSON 給前端。這個 JSON 的內容大致如下方所示。我們可以看出這個 JSON 的 message 欄位是對應到 exception.message。也就是說,欄位 status 和 error 都是我們無法控制的。而且,你也無法在這 JSON 中增加其他的欄位。我們將在本文章中,說明如何自訂義這個回傳給前端的 JSON 內容。
{
"timestamp": "2021-05-05T03:16:49.588+00:00",
"status": 403,
"error": "Forbidden",
"message": "Access is denied",
"path": "/path/to/api"
}假設我們在程式中自訂義以下的 exception 叫 AppException。而且,我們還新增一個參數 code。
class AppException(
val code: Int,
message: String? = null,
cause: Throwable? = null
) : Exception(message, cause)接下來,我們新增一個 class ExceptionHandler,並且在 ExceptionHandler 上加上 @ControllerAdvice annotation。@ControllerAdvice 是一種 @Component,特別是用來宣告 @ExceptionHandler、@InitBinder、和 @ModelAttribute 方法。所以,加上 @ControllerAdivce 後,ExceptionHandler 也就會是一個 bean。
再來,我們宣告 data class ExceptionResponse 來包含要回傳給前端的資料。ExceptionResponse 的結構與 Spring Boot 預設回傳給前端的 JSON 相似,但多了一個參數 code。
最後,我們宣告一個方法 handleAppRequest,並且加上 @ExceptionHandler annotation。在 @ExceptionHandler 中,指定要處理的 exception 的 class,即 AppException。
@ControllerAdvice
class ExceptionHandler {
data class ExceptionResponse(
val code: Int,
val status: Int,
val error: String,
val message: String,
val path: String,
val timestamp: Date = Date(),
)
@ExceptionHandler(AppException::class)
fun handleAppRequest(
exception: AppException,
request: HttpServletRequest,
): ResponseEntity<ExceptionResponse> {
return ResponseEntity(
ExceptionResponse(
exception.code,
HttpStatus.BAD_REQUEST.value(),
"Bad Request",
exception.message ?: "",
request.requestURI,
),
HttpStatus.BAD_REQUEST,
)
}
}我們看到 handleAppRequest() 回傳 ResponseEntity<ExceptionResponse>。我們也可以讓 handleAppRequest() 直接回傳 ExceptionResponse。其程式碼如下:
@ExceptionHandler(AppBadRequestException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
fun handleBadRequest(
exception: AppBadRequestException,
request: HttpServletRequest,
): ExceptionResponse {
return ExceptionResponse(
exception.code,
HttpStatus.BAD_REQUEST.value(),
"Illegal access",
exception.message ?: "",
request.requestURI,
)
}最後,用以下的程式碼丟出一個 exception 來看看回傳的結果。
throw AppBadRequestException(4, "Use is not allowed to access the resource")
前端會收到以下的 JSON 資料。
{
"code": 4,
"status": 400,
"error": "Illegal access",
"message": "Use is not allowed to access the resource",
"path": "/path/to/api",
"timestamp": "2021-05-05T04:30:12.754+00:00"
}









