在實際應用中,異常不是一個單一的概念,而是可以分為多種類型,每種類型的異常可能需要不同的處理邏輯。為了更好地管理和處理異常,我們可以將它們分為不同的類別,並為每個類別定義特定的處理方法。
通常,我們可以將異常分為兩大類別:業務異常和系統異常。
針對不同類型的異常,我們可以定義不同的處理邏輯,以確保我們能夠適當地應對各種情況。
以下是處理業務異常的示例程式碼:
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorDto handleBusinessException(BusinessException ex, HttpServletRequest request) {
ErrorDto errorDto = new ErrorDto();
errorDto.setTimestamp(LocalDateTime.now());
errorDto.setStatus(HttpStatus.BAD_REQUEST.value());
errorDto.setError("Bad Request");
errorDto.setMessage(ex.getMessage());
errorDto.setPath(request.getRequestURI());
return errorDto;
}
在這個示例中,我們捕獲了一個 BusinessException
,並返回一個帶有400 Bad Request狀態的錯誤DTO,其中包含有關業務異常的詳細信息。
以下是處理系統異常的示例程式碼:
@ExceptionHandler(SystemException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void handleSystemException(SystemException ex) {
// 無需返回具體的錯誤信息
}
在這個示例中,我們捕獲了一個 SystemException,並返回500 Internal Server Error,但不包含具體的錯誤信息。
通過將異常分為不同類型並定義相應的處理邏輯,我們可以更好地管理和處理異常,提高我們應用程式的可靠性和可維護性。這也有助於確保客戶端獲得有意義的錯誤信息,以更好地理解和處理問題。
在這個示例中,我們將創建一個簡單的 Spring Boot 應用程式,然後添加自定義異常處理,分為業務異常和系統異常兩類。
(1) 首先,讓我們創建一個 Spring Boot 應用程式:
(2) 創建一個名為 "ExceptionHandlingDemo" 的 Spring Boot 項目。
(3) 在pom.xml
文件中,確保你有以下相依性:
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
(4) 接下來,我們將創建自定義的業務異常和系統異常以及相應的異常處理器。
(4.1) 首先,創建一個 BusinessException
類,代表業務異常:
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
}
(4.2) 接著,創建一個 SystemException
類,代表系統異常:
public class SystemException extends RuntimeException {
public SystemException(String message) {
super(message);
}
}
(5) 現在,我們創建一個統一異常處理器,這個處理器將處理這兩種不同類型的異常。創建一個名為 GlobalExceptionHandler
的類:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorResponse handleBusinessException(BusinessException ex) {
return new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
}
@ExceptionHandler(SystemException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void handleSystemException(SystemException ex) {
// 不返回具體的錯誤信息
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleOtherExceptions(Exception ex) {
return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal Server Error");
}
}
在這個處理器中,我們使用 @ExceptionHandler
注解處理不同類型的異常。對於業務異常,我們返回一個包含錯誤信息的 ErrorResponse
物件,並將 HTTP 狀態設置為 400 Bad Request
。對於系統異常,我們不返回具體的錯誤信息,只是設置 HTTP 狀態為 500 Internal Server Error
。對於其他未處理的異常,我們也返回一個 ErrorResponse
物件,並設置 HTTP 狀態為 500。
(6) 最後,我們創建一個 ErrorResponse
類,用於包裝錯誤信息:
@Data // Lombok註解
@Builder // Lombok註解
public class ErrorResponse {
private int status;
private String message;
}
(7) 現在,我們可以在我們的應用程式中引發業務異常和系統異常,並確保它們由我們的自定義異常處理器處理。例如:
@RestController
@RequestMapping("/api")
public class BookController {
@GetMapping("/books/{id}")
public ResponseEntity<Book> getBook(@PathVariable Long id) {
// 模擬業務異常
if (id == 1) {
throw new BusinessException("Book not found with id " + id);
}
// 模擬系統異常
if (id == 2) {
throw new SystemException("Internal Server Error");
}
// 正常情況下返回書籍信息
Book book = new Book(id, "Sample Book");
return ResponseEntity.ok(book);
}
}
在這個示例中,我們創建了一個 BookController
並在 getBook
方法中引發了業務異常和系統異常。根據異常的類型,我們的自定義異常處理器會返回適當的 HTTP 狀態和錯誤信息。
在 Spring Boot 中,除了統一處理和返回異常信息外,日誌記錄對於診斷和追蹤應用程式中的異常情況也至關重要。 Spring Boot 集成了許多常見的日誌記錄框架,如 Logback、Log4j2 和 Java Util Logging,讓您可以輕松記錄異常信息。
以下是使用 Log4j2 作為日誌框架時,以下是如何配置和使用 Log4j2 來記錄異常信息的實踐步驟:
選擇 Log4j2 日誌框架: 確保您的 Spring Boot 項目中包含 Log4j2 的相關依賴,或者您可以在 pom.xml
文件中添加以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
配置 Log4j2: 在您的項目中,創建一個 Log4j2 配置文件,通常命名為 log4j2.xml
。您可以將該文件放置在項目的 src/main/resources
目錄下。以下是一個簡單的 log4j2.xml
配置示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="logs/exception.log">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
上面的配置示例將錯誤級別(error
)的日誌信息同時輸出到控制台和 logs/exception.log
文件中。
在異常處理中添加日誌記錄: 在您的自定義全局異常處理器方法中,使用 Log4j2 來記錄異常信息。例如:
@ControllerAdvice
public class GlobalExceptionHandler {
// ...
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorResponse handleBusinessException(BusinessException ex) {
// 記錄業務異常
Logger logger = LogManager.getLogger(GlobalExceptionHandler.class);
logger.error("BusinessException: " + ex.getMessage(), ex);
return new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
}
// ...
}
這裡,我們創建了一個 Logger
實例並使用 error
級別記錄異常信息。
集成監控和警報工具(可選): 根據您的項目需求,您還可以將 Log4j2 集成到監控和警報工具中,以實現更高級的異常監控和警報。
以上是使用 Log4j2 記錄異常信息的基本實踐步驟。通過選擇適當的日誌框架、配置日誌屬性、在異常處理中添加日誌記錄,您可以更好地追蹤和診斷應用程式中的異常情況,提高應用程式的可靠性和可維護性。
在這篇文章中,我們深入探討了 Spring Boot 中的統一異常處理的實踐。現在,讓我們回顧一下我們所學的主要知識點,並強調這些實踐的價值和優勢。
@ControllerAdvice
和 @ExceptionHandler
注解處理不同類型的異常情況。我們還演示了如何編寫通用的異常處理邏輯。統一異常處理和自定義錯誤頁面的實踐是開發 Web 應用程式不可或缺的一部分。它有助於提供更好的使用者體驗,確保應用程式能夠恢復正常運行,並簡化了錯誤處理程式碼的管理。
我們鼓勵您在自己的應用程式中實施良好的異常處理實踐,以提高使用者滿意度、提供更好的使用者反饋和快速解決問題。請記住,異常處理是不斷改進和調試的過程,因此要隨時準備應對新的挑戰和需求。