개요
컨트롤러에서 @RequestParam 어노테이션이나 @ModelAttribute 어노테이션을 붙이면 String 자료형이 다른 제네릭 타입으로 자동 형 변환되는 것을 확인할 수 있습니다.
이는 스프링에서 기본으로 제공해주는 TypeConverter 덕분인데 이번 게시글에서는 TypeConverter에 대해 알아보겠습니다.
1. 스프링 타입 컨버터
- HTTP 요청 파라미터는 모두 문자열로 처리
- 따라서, 요청 파라미터를 다른 제너릭 타입으로 변환하기 위해서는 변환하는 과정을 거쳐야 함
- 개요에서도 언급했듯이 @RequestParam, @ModelAttribute, @PathVariable 같은 어노테이션이 해당 과정을 대신해주기도 함
- 그 외 TypeConverter 적용 예시
- @Value 어노테이션을 통해 yml 정보 읽어올 때 (로컬, 개발, 운용 서버 설정이 각각 다르므로 yml 파일을 나누고 빌드할 때 각 서버의 맞는 값을 불러올 때 @Value 사용)
- View 렌더링 할 때
1.1 컨버터 인터페이스
- 스프링은 객체지향 원칙을 철저하게 지키므로 컨버터 인터페이스 또한 확장 가능하도록 제공
- 커스텀 인터페이스는 모든 타입에 적용할 수 있으며 S 타입에서 T 타입으로 변환하는 컨버터와 T 타입에서 S 타입으로 변환하는 컨버터 모두 구현 가능
- 입출력 타입에 제한이 없는 범용적인 타입 변환 기능을 제공
- 커스텀하게 컨버터를 구현하려면 해당 인터페이스를 구현해서 WebConfig에 등록해주면 됨
- WebConfig에 한번 등록한 이후에는 별도로 호출하지 않아도 자동으로 형 변환 지원
1.2 간단한 예시
- 생년월일을 저장하는 LocalDate 객체를 String 타입으로 변환하는 converter와
- String 타입을 생년월일을 나타내는 LocalDate 객체로 변환하는 converter를 구현
StringToBirthdayConverter
BirthdayToStringConverter
WebConfig
간단한 테스트 코드
1.3 ConversionService
- 앞선 테스트 코드처럼 구현한 TypeConverter를 매번 직접 찾아서 형 변환에 사용하는 것은 불편
- 따라서, 스프링은 개별 컨버터들을 모아 두고 그것들을 묶어서 편리하게 사용할 수 있도록 ConverionService를 제공
- ConversionService 인터페이스는 변환이 가능한지 유무 그리고 변환하는 메서드를 제공
- @RequestParam 어노테이션에서 자동으로 형 변환이 진행되는 것은 결국 @RequestParam을 처리하는 ArgumentResolver에서 ConversionService를 사용해서 타입을 변환
1.4 DefaultConversionService
- DefaultConversionService는 ConversionService를 구현하면서 converter를 등록하는 기능도 제공
- 객체지향 SOLID 법칙(https://jaimemin.tistory.com/1751) 중 인터페이스 분리 원칙에 따라 DefaultConversionService는 컨버터 사용에 초점을 둔 ConversionService와 컨버터 등록에 초점을 둔 ConverterRegistry를 구현
- 등록과 사용을 분리함에 따라 컨버터를 등록할 때는 구체적인 타입 컨버터를 명확하게 알아야 하지만 사용하는 입장에서는 TypeConverter에 대해 몰라도 됨 (훌륭한 객체지향 설계)
- 앞서 WebConfig에서 FormatterRegistry에 컨버터들을 등록했는데 FormatterRegistry를 타고 올라가면 결국 ConverionService를 구현하는 것을 확인할 수 있음
1.5 용도에 따른 다양한 컨버터
- Converter: 기본 타입 컨버터
- ConverterFactory: 전체 클래스 계층 구조가 필요할 때 사용하는 컨버터
- GenericConverter: 정교한 구현, 대상 필드의 어노테이션 정보 사용 가능한 컨버터
- ConditionalGenericConverter: 특정 조건이 참인 경우에만 실행하는 컨버터
- 보다 자세한 내용은 https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#core-convert 참고
2. 포맷터
- WebConfig 코드를 보면 FormatterRegistry에 컨버터를 등록하는 것을 확인할 수 있음
- 이는 곧 컨버터뿐만 아니라 포맷터 또한 WebConfig에 등록할 수 있다는 뜻
- Converter는 입출력 타입에 제한이 없는 범용적인 타입 변환 기능을 제공
- Formatter는 문자에 특화되며 Locale을 사용
- 10000 -> 10,000으로 변환한다던지
- LocalDateTime 객체 값인 2021-08-11 T 21:33:30를 2021.08.11 21:33:30으로 변환하는 것이 포맷터의 기능
- 정리를 하자면, 객체를 특정한 포맷에 맞추어 문자로 출력하거나 또는 그 반대의 역할을 하는 것에 특화된 것이 포맷터
2.1 포맷터 인터페이스
- Formatter는 객체를 문자로 혹은 문자를 객체로 변경하는 두 가지 기능을 모두 수행
* print 메서드: 객체를 문자로 변경
* parse 메서드: 문자를 객체로 변경
2.2 스프링에서 기본으로 제공하는 포맷터
- 앞서 언급한 예시 또한 기본으로 제공함 (NumberFormatter, DateTimeFormatter 등등)
- 스프링에서 아래 사진처럼 다양한 포맷터를 지원
- 포맷터는 기본 형식이 지정되어있기 때문에 객체의 각 필드마다 다른 형식으로 포맷을 지정하기 어렵기 때문에 스프링은 이런 문제를 해결해줄 어노테이션 기반 형식을 지원
- @NumberFormat: 숫자 관련 형식 지정 포맷터
- @DateTimeFormat: 날짜 관련 형식 지정 포맷터
@Data
public class Example {
@NumberFormat(pattern = "###,###,###")
private Integer digit;
@DateTimeFormat(pattern = "yyyy.MM.dd HH:mm:ss")
private LocalDateTime localDateTime;
}
2.3 FormattingConversionService
- ConversionService에는 converter만 등록 가능하고 formatter는 등록 불가능
- 하지만, 포맷터는 객체에서 문자 혹은 문자에서 객체로 변환시켜주는 컨버터의 일종이므로 formatter를 지원하는 ConversionService를 통해 등록해주면 됨
- FormattingConversionService를 통해 formatter를 등록해주면 되고 DefaultFormattingConversionService는 FormattingConversionService에 기본적인 통화, 숫자 관련 몇 가지 기본 formatter를 추가 제공
- 위에서 언급한 ConversionService는 내부에서 어댑터 패턴을 적용해 formatter가 converter처럼 동작하도록 지원
- 상속 관계를 정리하자면 아래와 같음
- FormattingConversionService는 ConversionService 관련 기능을 상속 받음
- 스프링 부트는 WebConversionService를 내부에서 사용하는데 이는 DefaultFormattingConversionService를 상속 받음
- 따라서, 앞서 converter 예시처럼 WebConfig에서 converter와 함께 formatter를 등록해주면 됨
- 주의할 점은 converter가 formatter보다 우선순위가 높으므로 비슷한 기능을 하는 converter가 있을 경우 formatter가 정상적으로 동작하지 않음
비고
- HttpMessageConverter의 경우 ConversionService 적용 안됨
- 예를 들자면, Jackson 라이브러리를 통해 HTTP의 메시지 바디 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력할 때 변환 과정은 해당 라이브러리에 의존적
- 커스텀 ConversionService를 구현해서 적용한다고 해도 영향이 없음
- 포맷은 전적으로 Jackson 라이브러리에 의존적
- 앞서 언급했듯이 ConversionService는 @RequestParam, @ModelAttribute, @PathVariable와 같은 어노테이션 혹은 View Template 등에서 사용 가능
출처
인프런 스프링 MVC 2편 (김영한 강사님)
반응형
'Spring' 카테고리의 다른 글
[SpringBoot] ThreadLocal 간단 정리 (0) | 2021.11.13 |
---|---|
[SpringBoot] 파일 업로드 및 다운로드 (2) | 2021.08.14 |
[SpringBoot] API 예외처리 (1) | 2021.08.08 |
[SpringBoot] HTML 예외처리와 예외 페이지 (0) | 2021.08.03 |
[SpringBoot] Filter, Interceptor 개념 정리 및 로그인 처리 (4) | 2021.08.01 |