본문 바로가기
스프링 부트3

스프링 부트 3의 글로벌 예외 처리

by 굿센스굿 2024. 12. 4.
반응형

 

스프링 부트 3에서는 글로벌 예외 처리(Global Exception Handling)를 통해 애플리케이션에서 발생하는 다양한 예외를 효율적으로 관리할 수 있습니다. 이 글에서는 스프링 부트 3에서 글로벌 예외 처리를 설정하고 사용하는 방법을 단계별로 설명하며, 주요 구현 방법과 실제 예제 3가지를 제공하겠습니다.


1. 글로벌 예외 처리란?

글로벌 예외 처리는 애플리케이션 전반에서 발생하는 예외를 중앙에서 처리하는 방식입니다. 이를 통해 코드 중복을 줄이고, 유지 보수성을 높이며, 사용자 경험을 향상시킬 수 있습니다.
스프링 부트에서는 @ControllerAdvice와 @ExceptionHandler를 사용하여 글로벌 예외 처리를 구성할 수 있습니다.


2. 글로벌 예외 처리 구현 단계

2.1 @ControllerAdvice의 역할

@ControllerAdvice는 특정 컨트롤러 혹은 애플리케이션 전체에서 발생하는 예외를 처리하기 위한 클래스에 사용됩니다. 글로벌 예외 처리 클래스에 선언하여 중앙에서 모든 예외를 관리할 수 있습니다.

2.2 @ExceptionHandler의 역할

@ExceptionHandler는 특정 예외 타입을 처리하기 위한 메서드에 적용됩니다. 처리하려는 예외 클래스와 연결하여 동작합니다.


3. 글로벌 예외 처리 예제

3.1 기본 예외 처리

예제 코드: GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
        return ResponseEntity.badRequest().body("잘못된 요청: " + ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneralException(Exception ex) {
        return ResponseEntity.internalServerError().body("서버에서 오류가 발생했습니다.");
    }
}
  • 설명:
    • IllegalArgumentException 발생 시 400 상태 코드를 반환.
    • 그 외의 일반적인 예외는 500 상태 코드를 반환.

예제 시나리오:

@GetMapping("/test")
public String testEndpoint(@RequestParam int value) {
    if (value < 0) {
        throw new IllegalArgumentException("음수는 허용되지 않습니다.");
    }
    return "값: " + value;
}
  • 결과:
    • /test?value=-1 호출 시: 400 Bad Request와 함께 잘못된 요청: 음수는 허용되지 않습니다. 반환.

3.2 사용자 정의 예외 처리

사용자 정의 예외 클래스

public class CustomNotFoundException extends RuntimeException {
    public CustomNotFoundException(String message) {
        super(message);
    }
}

글로벌 예외 처리 확장

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomNotFoundException.class)
    public ResponseEntity<String> handleCustomNotFoundException(CustomNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("리소스를 찾을 수 없습니다: " + ex.getMessage());
    }
}

예제 시나리오:

@GetMapping("/find")
public String findResource(@RequestParam String id) {
    if ("123".equals(id)) {
        return "리소스 찾음: " + id;
    } else {
        throw new CustomNotFoundException("ID " + id + "에 해당하는 리소스를 찾을 수 없습니다.");
    }
}
  • 결과:
    • /find?id=456 호출 시: 404 Not Found와 함께 리소스를 찾을 수 없습니다: ID 456에 해당하는 리소스를 찾을 수 없습니다. 반환.

3.3 예외 처리에 대한 공통 응답 구조

공통 응답 클래스 정의

public class ErrorResponse {
    private int status;
    private String message;
    private String timestamp;

    public ErrorResponse(int status, String message) {
        this.status = status;
        this.message = message;
        this.timestamp = LocalDateTime.now().toString();
    }

    // Getter, Setter 생략
}

글로벌 예외 처리에서 응답 구조 통일

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.INTERNAL_SERVER_ERROR.value(),
            ex.getMessage()
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

예제 시나리오:

@GetMapping("/error")
public String triggerError() {
    throw new RuntimeException("테스트 오류 발생");
}
  • 결과: JSON 형식으로 반환.
{
    "status": 500,
    "message": "테스트 오류 발생",
    "timestamp": "2024-12-03T12:00:00"
}

4. 글로벌 예외 처리의 장점

  1. 코드 중복 감소: 모든 컨트롤러에서 예외 처리 로직을 작성할 필요가 없습니다.
  2. 유지 보수성 향상: 예외 처리가 중앙에서 관리되므로 수정이 용이합니다.
  3. 응답 일관성 제공: 사용자에게 반환되는 에러 메시지와 형식을 통일할 수 있습니다.
  4. 테스트 용이성: 공통 로직으로 인해 예외 처리 테스트가 간소화됩니다.

스프링 부트 3에서 글로벌 예외 처리는 현대적인 애플리케이션의 안정성과 사용자 경험을 향상시키는 핵심 요소입니다. 위의 예제들을 활용하여 애플리케이션에 적합한 예외 처리 전략을 설계해 보세요!

반응형