본문 바로가기
Spring

Spring Day 21 : @ExceptionHandler, @ControllerAdvice, Spring 예외처리

by 우 석 2024. 2. 22.

ResponseEntity

 HTTP response object 를 위한 Wrapper로 HTTP status code, HTTP headers, HTTP body 를 담아 response로 반환한다.

 

@ExceptionHandler

Spring에서 예외처리를 위한 애너테이션. 특정 Controller에서 발생한 예외를 처리하기 위해 사용되며, @ExceptionHandler 가 붙어있는 메서드는 Controller에서 예외가 발생했을 때 호출 되며, 해당 예외를 처리하는 로직을 가진다.

AOP를 이용한 예외처리 방식이기때문에 각 메서드 마다 try catch할 필요없이 예외처리가 가능하다.


< Global 예외처리 >

예외처리 로직은 필요한 곳에서 Error를 만들어서 던지고, 그 Error를 받는곳에  Error 내용을 담아서 클라이언트에 보내준다. 에러처리를 하기 위해서 모든 Controller마다 예외처리를 해주는 것이 아니라, Global 하게 처리할 수 있다.

 

@ControllerAdvice 사용

Spring에서 예외처리를 위한 클래스 레벨 애너테이션. 모든 Controller에서 발생한 예외를 처리하기 위해 사용. @ControllerAdvice 가 붙은 클래스에서는 @ExceptionHandler메서드를 정의하여 예외를 처리하는 로직을 담을 수 있다.


@ControllerAdvice 를 사용하는 이유

  • 예외처리를 중앙 집중화.
  • 각각의 Controller에서 예외처리 로직을 반복하지 않아도 됨 -> 코드의 중복을 방지하고 유지보수성을 향상.
  • 예외 처리 로직을 모듈화하여 관리하기 쉽기 때문에, 팀 내에서 공통된 예외 처리 로직을 공유하거나 다른 팀에서 예외 리를 참고할 수 있다.

 

예외 처리 담당 클래스 (GlobalExceptionHandler.java)

GlobalExceptionHandler 클래스에 예외 처리를 담당하는

@RestControllerAdvice (@ControllerAdvice + @ResponseBod) 어노테이션을 추가했다.

 

각 예외 유형에 대한 처리 메서드가 정의되어 있으며, 해당 예외가 발생했을 때 적절한 응답을 반환한다.

 

정리하면 GlobalExceptionHandler 클래스는 예외 처리를 중앙 집중화하여 애플리케이션에서 발생할 수 있는 다양한 예외 상황을 처리한다.

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            MethodArgumentNotValidException e) {
        log.error("회원 검증 실패", e);
        String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        ErrorResponse errorResponse = new ErrorResponse(message);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }

    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<ErrorResponse> handleAuthenticationException(AuthenticationException e) {
        log.error("인증 실패", e);
        ErrorResponse errorResponse = new ErrorResponse(e.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }

    @ExceptionHandler(InvalidInputException.class)
    public ResponseEntity<ErrorResponse> handleInvalidInputException(InvalidInputException e) {
        log.error("잘못된 입력", e);
        ErrorResponse errorResponse = new ErrorResponse(e.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }

    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<String> handleUnhandledException(RuntimeException e) {
        log.error("처리되지 않은 예외 발생", e);
        return ResponseEntity.badRequest().body("Unhandled Exception");
    }
}
  • MethodArgumentNotValidException 예외가 발생한 경우 handleValidationException 메서드가 호출되며  유효성 검사 실패에 대한 처리를 담당한다. 예외 객체에서 실패한 검증 메시지를 가져와 ErrorResponse 객체를 생성하여 반환하며며 HTTP 상태 코드는 BAD_REQUEST로 설정한다.
  • AuthenticationException 예외가 발생한 경우 handleAuthenticationException 메서드가 호출되며  인증 실패에 대한 처리를 담당한다. 
  • InvalidInputException 예외가 발생한 경우 handleInvalidInputException 메서드가 호출되며  잘못된 입력에 대한 처리를 담당한다.
  • RuntimeException 예외가 발생한 경우 handleUnhandledException 메서드가 호출되며  처리되지 않은 예외에 대한 처리를 담당한다. 예외 객체와 함께 문자열 "Unhandled Exception" 을 반환하며. HTTP 상태 코드는 BAD_REQUEST로 설정한다.