'스프링 부트 @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 응답 코드를 설정할 수 있는 어노테이션입니다.
< 함께 보면 좋은 자료 >
< 참고 자료 >
'Programming > Spring Boot' 카테고리의 다른 글
SELECT FOR UPDATE / JPA를 사용한 비관적 잠금 (0) | 2022.02.06 |
---|---|
Spring Cache 캐시 추상화 기본적인 사용법 @Cacheable @CachePut @CacheEvict (0) | 2022.01.18 |
스프링 프레임워크 Reactive Stack, Servlet Stack 개념 (0) | 2021.12.28 |
RestTemplate Logging 요청과 응답 로그 남기기 (0) | 2021.12.23 |
Spring Boot Google OTP 2단계 보안인증 (Authenticator) 개념과 간단한 코드 (0) | 2021.12.20 |