SpringBoot에서 @ControllerAdvice, @RestControllerAdvice 활용해서 컨트롤러단의 예외를 전역으로 쉽게 관리할 수 있다.
먼저 @ControllerAdvice는 모든 @Controller가 선언된 클래스에 대한 예외를 전역으로 처리한다.
@RestControllerAdvice는 @ControllerAdvice + @ResponseBody 어노테이션이다. 따라서 단순 예외 처리가 아닌 응답 객체를 리턴해야 하는 경우 @RestControllerAdvice가 유용하다.
참고로 @ControllerAdvice, @RestControllerAdvice 모두 basePackageClasses, basePackages 속성을 통해 클래스나 패키지 단위로 제한할 수 있다.
@RestControllerAdvice(basePackages = "com.test.app")
그리고 Filter 같은 경우는 DispatcherServlet 외부에서 발생하기 때문에 @ControllerAdvice, @RestControllerAdvice가 아닌 별도 처리가 필요하다.
SpringBoot 기본 오류 메시지
별도 설정을 하지 않을 경우 SpringBoot 기본 오류 메시지는 application/json인 경우 아래와 같이 응답된다.
{
"timestamp": "2022-05-21T21:48:44.228+0000",
"status": 500,
"error": "error",
"message": "No message available",
"path": "/app/test"
}
@RestControllerAdvice 적용 예시
아래 클래스에서 선언된 각 메소드의 @ExceptionHandler에 선언한 Exception일 발생할 경우 @ResponseStatus로 선언된 응답 코드로 응답을 한다. 리턴값은 필요에 따라 객체를 선언하고 원하는 응답 메시지 형태를 구성할 수 있다. 아래 샘플 코드에 400에러 같은 경우는 Validation(@Valid) 실패 시 처리하는 핸들러로 BindingResult객체의 fieldError를 객체를 리턴하고, 나머지는 에러메시지를 리턴하도록 했다.
@RestControllerAdvice
public class RestExceptionAdvice {
// 400
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public JsonResponse bindException(BindException e) {
BindingResult bindingResult = e.getBindingResult();
return JsonResponse.makeJson(bindingResult.getFieldErrors());
}
// 404
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public JsonResponse notFoundException(Exception e) {
return JsonResponse.makeJson(e.getMessage());
}
// 405
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public JsonResponse methodNotAllowedException(Exception e) {
return JsonResponse.makeJson(e.getMessage());
}
// 406
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
public String notAcceptableException(Exception e) {
return e.getMessage();
}
// 415
@ExceptionHandler({HttpMediaTypeNotSupportedException.class})
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public JsonResponse unsupportedMediaTypeException(Exception e) {
return JsonResponse.makeJson(e.getMessage());
}
// 500, MyCustomException
@ExceptionHandler(MyCustomException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public JsonResponse userHandleException(MyCustomException e) {
return JsonResponse.makeJson(e.getMessage());
}
// 500, RuntimeException
@ExceptionHandler({RuntimeException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public JsonResponse systemException(Exception e) {
return JsonResponse.makeJson(e.getMessage());
}
}
404 Not Found 커스터마이징
404 Not Found를 커스터마이징 하기 위해서는 application.yml에 아래와 같은 설정이 추가되어야 @RestControllerAdvice로 적용이 가능하다.
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
Spring MVC Exception 정리
아래 응답 상태코드 별 Spring MVC Exception을 활용해서 필요에 따라 정의해서 사용하면 될 것 같다.
응답 상태 코드 | Spring MVC Exception | 설명 |
404 - Not Found | NoHandlerFoundException | 매핑 핸들러 없음 |
405 - Method Not Allowed | HttpRequestMethodNotSupportedException | 지원하지 않는 HTTP 메소드 |
406 - Not Acceptable | HttpMediaTypeNotAcceptableException | 요청 헤더의 Accept 미지원 |
415 - Unsupported Media Type | HttpMediaTypeNotSupportedException | 요청 헤더의 Content Type 미지원 |
400 - Bad Request | MethodArgumentNotValidException | @Valid 파라미터에 대해 검증 실패 |
400 - Bad Request | MissingServletRequestParameterException | 기대한 요청 Parameter를 찾지 못한 경우 발생 |
400 - Bad Request | TypeMismatchException | bean으로 값을 변경할 때, 핸들러가 예상한 class로 변경할 수 없는 경우 발생 |
400 - Bad Request | MissingServletRequestPartException | multipart/form-data 요청의 일부가 손실(can’t be found)되었을 때 발생 |
400 - Bad Request | HttpMessageNotReadableException | HttpMessageConverter에서 발생하며 read 메서드가 실패한 경우 발생 |
500 - Internal Server Error | MissingPathVariableException | 핸들러가 URL에서 기대한 Path Variable을 찾지 못한 경우 발생 |
500 - Internal Server Error | ConversionNotSupportedException | bean으로 요청 내용 변경을 위한 editor나 converter를 찾지 못한 경우 발생 |
500 - Internal Server Error | HttpMessageNotWritableException | HttpMessageConverter에서 발생하며 write 메서드가 실패한 경우 발생 |
참고: https://supawer0728.github.io/2019/04/04/spring-error-handling/
'개발 > SpringBoot' 카테고리의 다른 글
SpringBoot InMemory DB(H2) 사용 (0) | 2022.05.31 |
---|---|
SpringBoot Embedded Tomcat 세션 클러스터링 (0) | 2022.05.30 |
SpringBoot @RestControllerAdvice not working (0) | 2022.05.06 |
SpringBoot ResourceLoader 사용해서 classpath 파일 읽기 (0) | 2022.03.14 |
SpringBoot HikariCP 상태 log 보기 (0) | 2022.02.24 |
댓글