본문 바로가기
개발/SpringBoot

SpringBoot @RestControllerAdvice를 통한 예외 처리

by 궁즉변 변즉통 통즉구 2022. 5. 29.
반응형

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/

 

반응형

댓글