이런 문제들을 개선하기 위해서 @ExceptionHandler && @ControllerAdvice 등을 사용한다고 보면 이 과정을 이해하기 쉬울 것이다.
@ExceptionHandler 같은 경우 @Controller, @RestController가 적용된 Bean 내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 한다.
@RestController
public class MyRestController {
...
...
@ExceptionHandler(NullPointException.class)
public Object nullex(Exception e) {
System.out.println(e.getClass());
return "myService";
}
}
위 처럼 적용하기만 하면된다. @ExceptionHanlder annotation을 쓰고 인자로 캐치하고 싶은 예외 클래스를 등록해주면 된다.
📢 @ExceptionHandler({Exception1.class, Exception2.class}) 이런 식으로 두 개 이상도 등록이 가능하다
위 예제처럼 하면 MyRestController에 해당하는 Bean에서 NullPointerException이 발생하면, @ExceptionHandler(NullPointerException.class)가 적용된 메서드가 호출 될것이다.
@ExceptionHandler가 하나의 클래스에 대한 것이라면, @ControllerAdvice 는 모든 @Controller 즉, 전역에서 발생하는 예외를 잡아 처리해주는 어노테이션이다.
@RestControllerAdvice
public class Myadvice {
@ExceptionHandler(CustomException.class)
public String custom() {
return "hello custom";
}
}
위 처럼 새로운 클래스 파일을 만들어서 어노테이션을 붙이면 된다.
그 다음엔 @ExceptionHandler로 처리하고 싶은 예외를 잡아 처리한다
별도의 속성값이 없어 사용하면 모든 패키지 전역에 있는 컨트롤러를 담당하게 된다.
@RestControllerAdvice && @ControllerAdvice가 존재하는데 @RestControllerAdvice 어노테이션을 확인해보면
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
//...
}
@ControllerAdvice과 동일한 역할
즉, 예외를 잡아 핸들링 할 수 있도록 기능을 수행하면서 @ResponseBody를 통해 객체를 리턴할 수 도있다는 뜻이다.
ViewResolver를 통해서 예외 처리 페이지로 리다이렉트 시키면 @ControllerAdvice만 써도 되고, API 서버에서 에러 응답으로 객체를 리턴해야한다면 @ResponseBody 어노테이션이 추가된 @RestControllerAdvice 적용하면 되는 것이다
@RestController에서 예외가 발생하든 @Controller에서 예외가 발생하든 @ControllerAdvice && @ExceptionHandler 2개의 어노테이션으로 다 캐치할 수 있고, @ResponseBody의 필요 여부에 따라 적용하면 된다는 것이다.
만약 전역의 예외를 잡긴하되 패키지 단위로도 제한할 수 있다.
@RestControllerAdvice("com.example.demo.login.controller")
login 모듈에 있는 RestController에서 발생하는 예외를 잡으려면 이렇게 하면된다.