Skip to content

Latest commit

 

History

History
104 lines (58 loc) · 6.88 KB

File metadata and controls

104 lines (58 loc) · 6.88 KB

Spring MVC : 날짜 값, 변환, Exception 처리

이번 글에서는 @DateTimeFormat 애노테이션을 통해서 날짜 값 변환하는 것과 @ControllerAdvice, @ExceptionHandler를 통해서 에러 핸들링을 하는 방법에 대해서 알아보겠습니다.



@DateTimeFormat 타임 프로퍼티 변환 처리

스크린샷 2021-10-28 오후 1 33 16

최근에 프로젝트를 하면서 날짜 관련 타입으로 클라이언트로부터 받을 상황이 있었는데요. LocalDate 타입으로 쓸꺼면, 두 번째 메소드 처럼 LocalDate로만 받으면 되겠다! 라고 생각을 했습니다.


DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'; 
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type 
java.time.LocalDate] for value '2021-10-13'; nested exception is java.lang.IllegalArgumentException:

스크린샷 2021-10-28 오후 1 36 46

그래서 요청을 보내보니, 위의 에러가 발생합니다. 요약하면 String -> LocalDate 타입 변환을 할 수 없어서 에러가 발생했다는 것입니다. 스프링은 Long이나 int와 같은 기본 데이터 타입으로의 변환은 기본적으로 처리해주지만 LocalDateTime or LocalDate와 같은 타입으로의 변환은 추가 설정이 필요합니다.


스크린샷 2021-10-28 오후 1 42 02

이러한 상황일 때 @DateTimeFormat 애노테이션을 사용하면 @DateTimeFormat에서 지정한 형식을 이용해서 String -> LocalDate 타입으로 변환해줍니다. 아주 쉽쥬~?



@DateTimeFormat 변환 처리 과정

@DateTimeFormat 애노테이션을 사용하면 지정한 형식의 문자열을 LocalDate or LocalDateTime으로 변환해줄 수 있다고 위에서 정리했는데요. 그러면 누가 String -> LocalDate 타입으로 변환을 해주는 것일까요?

public class WebDataBinder extends DataBinder {}

바로 WebDataBinder가 그 역할을 하고 있습니다.


스크린샷 2021-10-28 오후 2 41 16

Spring MVC 디버깅 을 하는 것처럼 내부 과정을 따라가다 보니 위와 같이 WebDataBindercreate를 하는 구간이 존재하는 것을 볼 수 있습니다.


스크린샷 2021-10-28 오후 2 42 27

그리고 convertIfNeccesary 메소드는 이름에서 알 수 있듯이 필요하다면 convert를 하겠다라는 메소드인데요. 보면 arg에 제가 PathVariable을 통해서 넘긴 2021-11-01이 존재하는 것도 볼 수 있습니다.


스크린샷 2021-10-28 오후 2 43 00

이러한 과정 속에서 자세히 보면 WebDataBinder는 직접 변환 하지 않고 ConversionService에 그 역할을 위임합니다. (디버깅을 해보면 매우 복잡하다..)



@ControllerAdvice, @ExceptionHandler 사용하기

@ControllerAdvice를 사용하면 Spring 영역에서 발생하는 Exception들을 핸들링 할 수 있습니다. 제가 자주 보았던 Spring Guide - Exception 전략 에서도 어떻게 Exception 전략을 가져가면 좋은지에 대해서 설명하고 있습니다.

저 또한 RequestBody DTO 필드를 Valid 유효성 검사하기 에서 간단하게 @ControllerAdviceExceptionHandler를 통해서 예외 처리를 하는 것에 대해서 정리한 적이 있습니다.

이번 글에서도 비슷하게 위에서 살펴본 @DateTimeFormat 애노테이션이 없을 때 일어나는 Exception을 핸들링 하는 법에 대해서 정리해보겠습니다.


스크린샷 2021-10-28 오후 3 50 02

위와 같이 @ControllerAdvice 애노테이션을 사용하면 스프링 영역에서 발생하는 에러를 잡아 핸들링 할 수 있게 해줍니다. 예를들어, @DateTimeFormat이 없을 때 String -> LocalDate로 변환이 안되어 ConverterError가 발생하는데 이 때 MethodArgumentTypeMismatchException이 발생합니다.

즉, @ExceptionHandler를 통해서 MethodArgumentTypeMismatchException를 위와 같이 매칭시켜서 핸들링 시켜주면, MethodArgumentTypeMismatchException 에러가 발생했을 때 @ExceptionHandler에 정의한 함수가 호출되어 예외처리를 할 수 있습니다.



@ExceptionHandler 적용 메소드의 우선 순위

  • 같은 컨트롤러에 위치한 @ExceptionHandler 메소드 중 해당 Exception을 처리할 수 있는 메소드를 찾습니다.
  • 같은 클래스에 위치한 메소드가 Exception을 처리할 수 없을 경우 @ControllerAdvice 클래스에 위치한 @ExceptionHandler 메소드를 검색합니다.



ControllerAdvice 속성

스크린샷 2021-10-28 오후 3 59 29


스크린샷 2021-10-28 오후 3 59 53

@ControllerAdvice 애노테이션을 보면 위와 크게 3개의 속성이 존재하는데요. 정리하면 아래와 같습니다.


속성 타입 설명
value
basePackages
String[] 공통 설정을 적용할 컨트롤러가 속하는 기준 패키지
annotaions Class<? extends Annotations>[] 특정 애노테이션이 적용된 컨트롤러 대상
assignableTypes Class<?>[] 특정 타입 또는 그 하위 타입인 컨트롤러 대상