1. ResponseEntityExceptionHandler
공식문서는 이렇게 설명한다.
A class with an @ExceptionHandler method that handles all Spring MVC raised exceptions by returning a ResponseEntity with RFC 7807 formatted error details in the body.
번역하자면, RFC 7807 형식의 오류 세부 사항이 있는 ResponseEntity를 반환하여 모든 Spring MVC를 처리하는 @ExceptionHandler 메서드가 있는 클래스.
먼저 RFC 7807 을 알아보자.
2. RFC 7807
국제 인터넷 표준화 기구(IETF) 에서 관리하는 RFC 8707 은 HTTP API 의 표준이다.
3. 예외를 어떻게 관리하나
ResponseEntityExceptionHandler 클래스는 HTTP API 표준에 어긋나는 예외를 처리하는 클래스이다.
아래 코드는 해당 클래스 내부의 메소드이다.
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class
})
@Nullable
public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) throws Exception {
HttpHeaders headers = new HttpHeaders();
if (ex instanceof HttpRequestMethodNotSupportedException) {
HttpStatus status = HttpStatus.METHOD_NOT_ALLOWED;
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, headers, status, request);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
HttpStatus status = HttpStatus.UNSUPPORTED_MEDIA_TYPE;
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, headers, status, request);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
HttpStatus status = HttpStatus.NOT_ACCEPTABLE;
return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, headers, status, request);
}
else if (ex instanceof MissingPathVariableException) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleMissingPathVariable((MissingPathVariableException) ex, headers, status, request);
}
else if (ex instanceof MissingServletRequestParameterException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, headers, status, request);
}
else if (ex instanceof ServletRequestBindingException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleServletRequestBindingException((ServletRequestBindingException) ex, headers, status, request);
}
else if (ex instanceof ConversionNotSupportedException) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleConversionNotSupported((ConversionNotSupportedException) ex, headers, status, request);
}
else if (ex instanceof TypeMismatchException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleTypeMismatch((TypeMismatchException) ex, headers, status, request);
}
else if (ex instanceof HttpMessageNotReadableException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, headers, status, request);
}
else if (ex instanceof HttpMessageNotWritableException) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, headers, status, request);
}
else if (ex instanceof MethodArgumentNotValidException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleMethodArgumentNotValid((MethodArgumentNotValidException) ex, headers, status, request);
}
else if (ex instanceof MissingServletRequestPartException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleMissingServletRequestPart((MissingServletRequestPartException) ex, headers, status, request);
}
else if (ex instanceof BindException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
return handleBindException((BindException) ex, headers, status, request);
}
else if (ex instanceof NoHandlerFoundException) {
HttpStatus status = HttpStatus.NOT_FOUND;
return handleNoHandlerFoundException((NoHandlerFoundException) ex, headers, status, request);
}
else if (ex instanceof AsyncRequestTimeoutException) {
HttpStatus status = HttpStatus.SERVICE_UNAVAILABLE;
return handleAsyncRequestTimeoutException((AsyncRequestTimeoutException) ex, headers, status, request);
}
else {
// Unknown exception, typically a wrapper with a common MVC exception as cause
// (since @ExceptionHandler type declarations also match first-level causes):
// We only deal with top-level MVC exceptions here, so let's rethrow the given
// exception for further processing through the HandlerExceptionResolver chain.
throw ex;
}
}
이 메소드는 위에서 언급했듯 HTTP API 표준에 어긋난 경우 발생하는 예외를 잡아준다.
4. 나의 생각
당연히 MethodArgumentNotValidException.class 만 이용해 예외를 처리했었다. 하지만 이미 Spring 에서 지원을 해주고 있었고 Spring 기능이 진짜 많은 것 같다고 느낀 부분이었다.
ResponseEntityExceptionHandler 를 사용해도 좋냐라고 물을 땐, Yes 다.
상속 받는 클래스가 다양한 커스텀 예외(어플리케이션의 요청과 응답을 처리할 때 발생할)를 만들어서,
handle 메소드를 추가한다면 그 클래스는 탄탄한 HTTP 통신을 위한 전역 예외 처리 클래스가 될 것이다.
'spring' 카테고리의 다른 글
@WebMvcTest 는 어떻게 Controller 관련 bean 들만 등록할까? (2) | 2023.04.28 |
---|---|
spring boot - oracle wallet (0) | 2022.04.10 |
Gradle (0) | 2022.02.14 |
Maven 과 Gradle (0) | 2022.02.14 |