💋 인트로
이전 포스팅에서 Spring의 @Controller에서 예외 처리를 하는 방법에 대해서 공부했다.
지정한 예외를 잡아서 처리할 수 있는 기능을 얻었지만, 우리가 만드는 애플리케이션은 여러 개의 컨트롤러를 가질 때가 많다. 컨트롤러가 여러 개인 경우, 어떻게 될까?
@ExceptionHandler는 코드가 작성된 @Controller 내에서만 작동한다. 다른 컨트롤러에서 동일한 예외가 발생했더라도 잡을 수가 없다. IllegalArgumentException에 대해 동일한 처리를 해주고 싶더라도, 그 예외가 다른 컨트롤러에서 발생한다면 같은 작업을 중복해서 넣어 주어야 하기 때문에 상당히 번거롭다.
이것을 해결하기 위해 등장한 것이 @ControllerAdvice이다!
💋 @ControllerAdvice가 등장한 이유
@ControllerAdvice는 애플리케이션에서 전역적으로 예외를 처리하기 위해 만들어졌다.
이 어노테이션을 사용하여 예외 처리 과정을 중앙 집중화할 수 있어서, 모든 컨트롤러에서 발생하는 예외를 한 곳에서 처리할 수 있다.
💋 @ControllerAdvice 사용 방법
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointerException(NullPointerException e) {
return new ResponseEntity<>("NullPointerException occurred: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@ControllerAdvice는 많은 컨트롤러에서 공통으로 발생할 수 있는 예외 상황에 대해 반복적인 예외 처리 코드 작성을 방지한다. @ControllerAdvice 어노테이션은 모든 컨트롤러에서 예외가 발생한다면 핸들링을 담당할 핸들링 전용 Controller에 선언하는 어노테이션이며, 전역적으로 ExceptionHandler를 적용해준다.
참고: 스프링 3.2 버전 이상부터 추가된 기능이므로, 만약 해당 어노테이션이 import 되지 않는다면 버전을 확인해야 한다.
@ControllerAdvice는 @Controller 어노테이션이 있는 모든 클래스에서 발생하는 예외를 잡을 수 있다.
하지만 특정 컨트롤러나 패키지에서만 예외를 잡도록 하고싶다면???
💋 특정 클래스에서 발생하는 예외만 받아서 처리하게 하는 @ControllerAdvice
basePackageClasses나 basePackages 속성을 이용하여 특정 클래스에서 발생하는 예외만을 받아서 처리할 수 있다.
예를 들어, com.example.controller 패키지 내의 MyController 클래스에서 발생하는 예외만을 처리하도록 하려면, 다음과 같이 @ControllerAdvice 어노테이션을 사용할 수 있다.
@ControllerAdvice(basePackageClasses = MyController.class) // 속성 추가
public class MyControllerAdvice {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
이렇게 하면, MyController 클래스에서 발생하는 예외와 그 하위 클래스들만을 처리하는 MyControllerAdvice 클래스가 정의된다.
이 방법도 만능은 아니다.
패키지는 구조가 달라지는 경우가 있는데, 패키지 구조가 달라지는 경우 예외 처리가 제대로 안될 수 있다.
또한, 패키지 구조가 복잡해지면 basePackages 속성으로 여러 패키지를 지정해 줘야 하는 번거로움도 있다.
참고로, @ControllerAdvice가 할 수 있는 일은 아래와 같다.
- @ExceptionHandler 어노테이션을 사용하여 예외 처리 메소드를 정의할 수 있다.
- @InitBinder 어노테이션을 사용하여 모든 컨트롤러에서 사용할 수 있는 바인딩 설정 메소드를 정의할 수 있다.
- @ModelAttribute 어노테이션을 사용하여 모든 컨트롤러에서 사용할 수 있는 모델 어트리뷰트 메소드를 정의할 수 있다.