스프링 애플리케이션에서 Controller 내에서 글로벌하게 발생하는 예외를 ControllerAdvice
를 사용해 핸들링 할 수 있다.
우선 ControllerAdvice란?
특정 패키지나 컨트롤러, 나아가서 컨트롤러 단에서 글로벌하게 발생하는 예외를 공통적으로 처리할 수 있는 어노테이션이다.
우선 실습을 위해 컨트롤러를 생성해보자.
@RestController
@RequestMapping("/api/exception")
class ExceptionApiController {
@GetMapping("/test")
fun controllerAdvice() {
val list = mutableListOf<String>()
val temp = list[0]
}
}
일부로 예외를 내도록 빈 리스트에서 0번째 인덱스를 가져오게 해보자. IndexOutOfBoundsException
exception이 발생함을 예측할 수 있다.
로컬에서 서버를 구동시킨 다음에 Postman으로 방금 작성한 api를 호출해보자.
역시나 기본 500, Internal Server Error
가 발생한다. 로그를 확인해보면 전형적으로 핸들링 처리가 되지 않은 인덱스 에러가 발생함을 확인할 수 있다.
이제 ControllerAdvice 어노테이션을 사용해 발생한 위 예외를 핸들링해보자.
advice
패키지를 생성해 GlobalControllerAdvice
클래스를 생성한다
@RestControllerAdvice
class GlobalControllerAdvice {
@ExceptionHandler(value = [IndexOutOfBoundsException::class])
fun indexOutOfBoundException(e: IndexOutOfBoundsException): String {
return "Index Error 발생"
}
}
@RestControllerAdvice
어노테이션을 달아주면 해당 클래스는 ControllerAdvice
의 역할을 하게 된다. @ExceptionHandler
어노테이션을 사용한다 value
안에는 따로 핸들링하고 싶은 Exception
을 Array
로 받는다. 여기서는 IndexOutOfBoundsException
만 필요하므로 위 같이 작성해준다. Exception
을 처리하고 싶다면 @ExceptionHandler
를 아래와 같이 작성할 수 있다.@ExceptionHandler(value = [IndexOutOfBoundsException::class, RuntimeException::class])
서버를 다시 재가동 시킨 후 똑같이 api를 호출해보자.
IndexOutOfBoundsException
가 따로 핸들링 되었다. 하지만 200 응답을 내주는건 조금 이상하니까 따로 500용 ResponseEntity
를 반환해서 처리해주자.
@RestControllerAdvice
class GlobalControllerAdvice {
@ExceptionHandler(value = [IndexOutOfBoundsException::class])
fun indexOutOfBoundException(e: IndexOutOfBoundsException): ResponseEntity<String>{
return ResponseEntity.internalServerError().body("Index Error 발생")
}
}
그리고 다시 호출해보면 아래와 같이 500 response code와 함께 핸들링한 메세지로 응답이 오는 부분을 확인할 수 있다.
위 처럼 글로벌하게 정의해 애플리케이션의 컨트롤러에서 발생하는 모든 예외를 처리할수도 있지만 특정 패키지나, 컨트롤러에 한해서만 에러핸들링 처리가 가능하다.
@ResControllerAdvice
어노테이션에서 basePackageClasses
를 활용해주면 된다.
예시) PutApiController
내부에서만 에러 핸들링을 제한해보기
@RestControllerAdvice(basePackageClasses = [PutApiController::class])
class PutApiControllerAdvice