Spring

[SpringBoot] 스프링 TypeConverter 정리

꾸준함. 2021. 8. 11. 22:01

개요

컨트롤러에서 @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 용도에 따른 다양한 컨버터

 

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편 (김영한 강사님)

반응형