Programming/Spring Boot

Spring Boot 예외 처리 @ControllerAdvice, @ExceptionHandler

Jan92 2021. 12. 30. 01:03

'스프링 부트 @ControllerAdvice, @ExceptionHandler를 이용한 예외 처리'

 

프로그래밍에서 예외처리는 아주 중요한 부분입니다. 예외가 발생할 수 있는 부분에서 예외를 잡아서 세밀하게 처리해준다면 클라이언트 측면에서와 서버 측면에서 모두 더 안정적인 프로그램이 될 수 있습니다.

일반적으로 예외를 처리해야 하는 상황에서 각각의 예외들을 메서드 단에서 try-catch 또는 throw로 처리하게 되면 코드가 복잡해질 수밖에 없습니다. 이러한 문제를 개선하기 위해 Spring Boot에서는 @ExceptionHandler, @ControllerAdvice(+ @RestControllerAdvice)를 사용합니다.

 

 

 

@RestController
@RequiredArgsConstructor
@RequestMapping("/webClient")
public class WebClientController {

  ...

  @ExceptionHandler(IllegalStateException.class)
  public ResponseEntity<?> catchException(Exception e) {
    System.out.println("e class" + e.getClass());
    return null;
  }
}

@ExceptionHandler

먼저 @ExceptionHandler 같은 경우에는 @Controller, @RestController가 적용된  Bean 내에서 발생하는 예외를 잡아 하나의 메서드에서 처리해주는 기능을 합니다.

(Controller 단에서만 사용 가능하며, @Service 등 다른 곳에서는 사용할 수 없습니다.)

 

@ExceptionHandler({IllegalStateException.class, NullPointerException.class})

사용법은 @ExceptionHandler 어노테이션 안에 인자로 캐치하고 싶은 예외 클래스를 등록해주면 되며, 위 같은 방식으로 두 개 이상의 예외도 등록할 수 있습니다.

 

 

* 정리하자면 해당하는 Controller 안에서 발생하는 Exception 중 ExceptionHandler에 등록된 Exception을 모두 해당 메서드를 통해 처리하는 방식입니다.

(WebClientController 안에서 발생하는 모든 IllegalStateException을 catchException() 메서드에서 처리합니다.)

 

 


 

 

@RestControllerAdvice
public class ExceptionAdvice {

    ...

    @ExceptionHandler(NotFoundException.class)
    public ResponseEntity<?> notFoundException() {
        ...
    }

    @ExceptionHandler(SecurityException.class)
    public ResponseEntity<?> SecurityException(Exception e) {
        ...
    }

    @ExceptionHandler
    public ResponseEntity<?> defaultException(Exception e) {
        ...
    }
}

@ControllerAdvice, @RestControllerAdvice

다음으로 프로젝트 전역에서 발생하는 예외를 한 곳에서 처리하는 방법입니다.

@ControllerAdvice 어노테이션을 통해 모든 컨트롤러에서 발생하는 예외를 잡습니다. 그리고 @ExceptionHandler 어노테이션을 통해 발생하는 예외의 종류마다 처리할 메서드를 정의합니다. 설정이 완료되면 Controller에서 예외 처리하는 코드를 작성하지 않아도 @ControllerAdvice 어노테이션이 적용된 ExceptionAdvice 클래스에서 예외를 잡아서 처리하게 됩니다.

(만약 예외가 발생하는 메서드에서 try-catch를 통해 예외를 직접 처리하면 가까이 있는 try-catch의 예외처리가 우선순위로 작동합니다.)

 

 

@RestControllerAdvice("com.example.exception.api.test")

위 코드처럼 @ControllerAdvice 어노테이션 안에 범위를 지정해줌으로써 패키지 단위로 예외를 잡을 수도 있습니다.

(패키지 구성과 예외 범위를 생각해서 구조를 짜면 잘 활용할 수 있습니다.)

 

 

***

@ControllerAdvice와 @RestControllerAdvice의 차이는 무엇일까요?

 

먼저 알아야할 것은 @Controller에서 발생하는 예외를 @RestControllerAdvice에서 잡을 수 있고, 반대로 @RestController에서 발생한 예외를 @ControllerAdvice에서 잡을 수 있다는 것입니다.

@RestControllerAdvice 어노테이션에는 @ControllerAdvice 어노테이션과 @ResponseBody 두 개의 어노테이션이 모두 포함되어 있습니다. 이것은 @ControllerAdvice와 동일한 역할 즉, 예외를 잡아 핸들링할 수 있도록 하는 기능을 수행하면서 @ResponseBody를 통해 객체를 리턴할 수도 있다는 의미입니다.

 

결론적으로 API 서버의 역할로 에러 응답 객체를 리턴해야 한다면 JSON 형식으로 변환하기 위해 @RestControllerAdvice 어노테이션을 사용해야 하고, viewResolver를 통해서 바로 예외 처리 페이지를 보여준다고 하면 @ControllerAdvice 어노테이션을 사용해야 합니다.

 

 


 

@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ResponseStatus(code = HttpStatus.FORBIDDEN)

@ResponseStatus

예시에서 자주 함께 등장하는 @ResponseStatus는 컨트롤러나 예외에 사용하여 HTTP 응답 코드를 설정할 수 있는 어노테이션입니다.

 

 

 

 

< 함께 보면 좋은 자료 >

 

자바 예외 처리 방법과 CheckedException, UncheckedException

*** Throwable 클래스는 예외 처리를 하기 위한 최상위 클래스로, 직접 사용되는 경우는 없지만 Throwable 타입과 이 클래스를 상속받은 서브 타입만이 JVM이나 throw 키워드에 의해 던져질 수 있습니다.

wildeveloperetrain.tistory.com

 

 

< 참고 자료 >

 

[Spring]컨트롤러 예외처리를 자동으로

Controller 를 작성하다 보면 예외처리를 반복적으로 작성해야할 때가 있다.예를 들어 IllegalArgumentException일 경우 400(BadRequest)를 응답한다거나 알 수 없는 Exception 의 경우 500(INTERNAL_SERVER_ERRO

velog.io

 

 

@ControllerAdvice, @ExceptionHandler를 이용한 예외처리 분리, 통합하기(Spring에서 예외 관리하는 방법, 실

예외 처리 과정 프로그래밍에서 예외 처리는 아주 중요하면서도 아주 어렵다. 과하다할 만큼 상세하고 다양하게 예외를 잡아 처리해준다면, 클라이언트도 그렇고 서버도 그렇고 더 안정적인 프

jeong-pro.tistory.com