Xử Lỗi Toàn Cục trong Spring Boot: Hướng Dẫn Chi Tiết

Đăng ngày: 14-10-2025 18:24
exception handlingSpring BootXử lý lỗi@ControllerAdvice@RestControllerAdviceAPIWebLỗi toàn cụcGlobal Exception Handler

Chào mừng bạn đến với bài viết thứ 11 trong series về Spring và Spring Boot! Hôm nay, chúng ta sẽ khám phá một khía cạnh quan trọng: xử lý lỗi toàn cục. Trong quá trình phát triển ứng dụng, việc xử lý lỗi một cách hiệu quả là vô cùng quan trọng. Nó giúp ứng dụng hoạt động ổn định hơn và cung cấp trải nghiệm người dùng tốt hơn. Chúng ta sẽ tìm hiểu cách xây dựng một cơ chế xử lý lỗi tập trung và chuyên nghiệp.

Tại sao cần Xử lý Lỗi Toàn cục?

Trong một ứng dụng lớn, việc xử lý lỗi rải rác trong từng controller hoặc service sẽ gây khó khăn cho việc bảo trì. Khi có một lỗi phát sinh, chúng ta phải tìm kiếm và sửa chữa ở nhiều nơi khác nhau. Điều này tốn thời gian và công sức. Hơn nữa, việc xử lý lỗi không nhất quán có thể dẫn đến trải nghiệm người dùng không tốt. Một số lỗi có thể hiển thị thông báo khó hiểu, trong khi một số khác lại không được xử lý đúng cách.

Xử lý lỗi toàn cục giúp chúng ta tập trung việc xử lý lỗi vào một hoặc một vài vị trí. Điều này giúp mã nguồn dễ đọc, dễ bảo trì và dễ kiểm soát hơn. Chúng ta có thể áp dụng các quy tắc xử lý lỗi chung cho toàn bộ ứng dụng. Ví dụ, chúng ta có thể ghi log lỗi, trả về mã trạng thái HTTP phù hợp và hiển thị thông báo lỗi thân thiện cho người dùng.

Sử dụng @ControllerAdvice và @RestControllerAdvice

Spring cung cấp hai annotation mạnh mẽ là @ControllerAdvice và @RestControllerAdvice để giúp chúng ta xử lý lỗi toàn cục. Cả hai annotation này đều cho phép chúng ta bắt các exception xảy ra trong ứng dụng. Tuy nhiên, chúng có một chút khác biệt về cách xử lý phản hồi.

@ControllerAdvice thường được sử dụng cho các ứng dụng web truyền thống, nơi chúng ta trả về các trang HTML. Khi một exception xảy ra, chúng ta có thể sử dụng @ExceptionHandler để bắt exception và trả về một trang lỗi tùy chỉnh.

@RestControllerAdvice thường được sử dụng cho các ứng dụng API, nơi chúng ta trả về dữ liệu JSON. Khi một exception xảy ra, chúng ta có thể sử dụng @ExceptionHandler để bắt exception và trả về một response JSON chứa thông tin lỗi.

Ví dụ với @RestControllerAdvice

Hãy xem một ví dụ về cách sử dụng @RestControllerAdvice để xử lý lỗi trong một ứng dụng API.

Đầu tiên, chúng ta tạo một class đánh dấu bằng annotation @RestControllerAdvice.


@RestControllerAdvice
public class GlobalExceptionHandler {

}

Tiếp theo, chúng ta tạo một method để xử lý một exception cụ thể. Chúng ta sử dụng annotation @ExceptionHandler để chỉ định loại exception mà method này sẽ xử lý.


@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
        ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }
}

Trong ví dụ này, chúng ta xử lý exception ResourceNotFoundException. Khi exception này xảy ra, method handleResourceNotFoundException sẽ được gọi. Method này tạo một đối tượng ErrorResponse chứa mã trạng thái HTTP và thông báo lỗi. Sau đó, nó trả về một ResponseEntity chứa đối tượng ErrorResponse và mã trạng thái HTTP 404 (Not Found).

ErrorResponse là một class đơn giản để chứa thông tin lỗi:


public class ErrorResponse {
    private int statusCode;
    private String message;

    public ErrorResponse(int statusCode, String message) {
        this.statusCode = statusCode;
        this.message = message;
    }

    // Getters and setters
}

Bây giờ, khi một ResourceNotFoundException xảy ra trong bất kỳ controller nào, GlobalExceptionHandler sẽ bắt exception và trả về một response JSON như sau:


{
  "statusCode": 404,
  "message": "Resource not found"
}

Điều này cung cấp một phản hồi lỗi chuẩn hóa và dễ hiểu cho người dùng API.

Ví dụ với @ControllerAdvice

Tương tự, chúng ta có thể sử dụng @ControllerAdvice để xử lý lỗi trong một ứng dụng web truyền thống.


@ControllerAdvice
public class GlobalWebExceptionHandler {

    @ExceptionHandler(Exception.class)
    public String handleException(Exception ex, Model model) {
        model.addAttribute("errorMessage", ex.getMessage());
        return "error"; // Returns the name of the error view (error.html)
    }
}

Trong ví dụ này, chúng ta xử lý tất cả các exception (Exception.class). Khi một exception xảy ra, method handleException sẽ được gọi. Method này thêm thông báo lỗi vào model và trả về tên của view lỗi (error.html). View lỗi sẽ hiển thị thông báo lỗi cho người dùng.

Các loại Exception thường gặp

Dưới đây là một số loại exception thường gặp mà bạn có thể muốn xử lý:

  • ResourceNotFoundException: Khi một tài nguyên không tìm thấy.
  • IllegalArgumentException: Khi một tham số không hợp lệ được truyền vào method.
  • AuthenticationException: Khi người dùng không được xác thực.
  • AuthorizationException: Khi người dùng không có quyền truy cập vào tài nguyên.
  • DataAccessException: Khi có lỗi xảy ra khi truy cập vào cơ sở dữ liệu.

Lời khuyên và Mẹo

  • Hãy xác định các loại exception quan trọng nhất cần xử lý trong ứng dụng của bạn.
  • Sử dụng mã trạng thái HTTP phù hợp để chỉ ra loại lỗi.
  • Cung cấp thông báo lỗi rõ ràng và dễ hiểu cho người dùng.
  • Ghi log lỗi để giúp bạn theo dõi và sửa chữa các vấn đề.
  • Sử dụng các exception tùy chỉnh để thể hiện các lỗi cụ thể trong ứng dụng của bạn.

Kết luận

Xử lý lỗi toàn cục là một phần quan trọng của việc xây dựng một ứng dụng Spring Boot mạnh mẽ và đáng tin cậy. Bằng cách sử dụng @ControllerAdvice và @RestControllerAdvice, bạn có thể tập trung việc xử lý lỗi và cung cấp trải nghiệm người dùng tốt hơn. Hãy bắt đầu áp dụng những kiến thức này vào dự án của bạn ngay hôm nay để nâng cao chất lượng ứng dụng!

0 Bình luận