[Spring] 컨버터와 포맷터 (컨버전 서비스, 스프링 기본 제공 포맷터)
컨버터
새로운 타입을 만들어 변환하고 싶을 때, 컨버터를 만들어 등록하면 쉽게 사용할 수 있다.
컨버터 인터페이스
public interface Converter<S, T> {
T convert(S source);
}
`S` 타입에서 `T` 타입으로 변환하는 것이다.
> 참고 <
`org.springframework.core.convert.converter` 를 사용해야 한다.
사용 예시
@Getter
@EqualsAndHashCode
public class IpPort {
private String ip;
private int port;
public IpPort(String ip, int port) {
this.ip = ip;
this.port = port;
}
}
public class IpPortToStringConverter implements Converter<IpPort, String> {
@Override
public String convert(IpPort source) {
return source.getIp() + ":" + source.getPort();
}
}
public class StringToIpPortConverter implements Converter<String, IpPort> {
@Override
public IpPort convert(String source) {
// "127.0.0.1:8080"
String[] split = source.split(":");
String ip = split[0];
int port = Integer.parseInt(split[1]);
return new IpPort(ip, port);
}
}
IpPort 객체를 String 으로 변환하는 컨버터와,
String 을 IpPort 객체로 변환하는 컨버터이다.
컨버전 서비스
ConversionService 는 개별 컨버터를 묶어서 편리하게 사용할 수 있는 기능을 제공한다.
DefaultConversionService
`ConversionService` : 컨버터 사용
`ConversionRegistry` : 컨버터 등록
두 인터페이스를 구현하였다.
사용 방법
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
assertThat(conversionService.convert("127.0.0.1:8080", IpPort.class))
.isEqualTo(new IpPort("127.0.0.1", 8080));
assertThat(conversionService.convert(new IpPort("127.0.0.1", 8080), String.class))
.isEqualTo("127.0.0.1:8080");
컨버터 등록 시에는 타입 컨버터를 명확히 알아야 하지만,
컨버터 사용 시에는 타입 컨버터를 모른 채로 `convert()` 를 사용하면 된다.
WebMvcConfigurer
스프링은 내부에서 ConversionService 를 제공한다.
WebMvcConfigurer 가 제공하는 `addFormatters()` 를 사용해서 추가하고 싶은 컨버터를 등록하면,
스프링이 ConversionService 에 컨버터를 추가해 준다.
포맷터
객체를 특정 포맷에 맞추어 문자로 출력할 때(또는 그 반대) 특화된 기능이 포맷터이다.
포맷터 인터페이스
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
`print()` : 객체를 문자로 변경
`parse()` : 문자를 객체로 변경
사용 예시
public class MyNumberFormatter implements Formatter<Number> {
@Override
public Number parse(String text, Locale locale) throws ParseException {
NumberFormat format = NumberFormat.getInstance(locale);
return format.parse(text);
}
@Override
public String print(Number object, Locale locale) {
return NumberFormat.getInstance(locale).format(object);
}
}
`NumberFormat` 은 숫자 중간에 가독성을 위한 쉼표를 적용해 주는 포맷터로 자바가 기본으로 제공하는 객체이다.
여기서 `Locale` 정보를 통해 나라별로 다른 숫자 포맷을 만들어 준다.
> 참고 <
Number 타입은 Integer, Long 같은 숫자 타입의 부모 클래스이다.
포맷터 지원 컨버전 서비스
내부에서 어댑터 패턴을 사용하여 포맷터도 컨버터처럼 동작하도록 지원한다.
DefaultFormattingConversionService
`FormattingConversionService` : 포맷터를 지원하는 컨버전 서비스 (ConversionService 관련 기능 상속받음)
+ 기본적인 통화, 숫자 관련 기본 포맷터를 추가하여 제공
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
conversionService.addFormatter(new MyNumberFormatter());
assertThat(conversionService.convert("127.0.0.1:8080", IpPort.class))
.isEqualTo(new IpPort("127.0.0.1", 8080));
assertThat(conversionService.convert(1000, String.class)).isEqualTo("1,000");
assertThat(conversionService.convert("1,000", Long.class)).isEqualTo(1000L);
WebConversionService
스프링 부트는 내부에서 DefaultFormattingConversionService 를 상속받은 WebConversionService 를 사용한다.
스프링 제공 기본 포맷터
스프링은 애노테이션 기반으로 원하는 형식을 지정해서 사용할 수 있는 포맷터를 제공한다.
`@NumberFormat` : 숫자 관련 형식 포맷터 사용 (NumberFormatAnnotationFormatterFactory 사용됨)
`@DataTimeFormat` : 날짜 관련 형식 지정 포맷터 사용 (Jsr310DateTimeFormatAnnotationFormatterFactory 사용됨)
@Data
class Form {
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
타임리프 사용
`*{{...}}` : 컨버전 서비스를 적용하여 변환된 결과로 조회
`th:field="${...}"` : value 속성이 컨버젼 서비스를 적용하여 변환된 값을 갖는다.
> 참고 <
HttpMessageConverter 는
HTTP 메시지 바디 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력하는 것이기 때문에
컨버전 서비스가 적용되지 않는다.
컨버전 서비스 `@RequestParam`, `@ModelAttribute`, `@PathVariable`, `뷰 템플릿` 등
메시지 컨버터 `@RequestBody`, `@ResponseBody`, `HttpEntity`, `ResponseEntity` 등
출처 | 스프링 MVC 2(김영한) - 인프런