@GetMapping("/hello-v2")
public String helloV2(@RequestParam Integer data) {
System.out.println("data = " + data);
return "ok";
}
@ModelAttribute UserData data
class UserData {
Integer data;
}
/users/{userId}
@PathVariable("userId") Integer data
위 예시들을 보면 문자를 숫자로 편하게 받을 수 있다
이는 스프링이 중간에서 타입을 변환해주기 때문이다
직접 새로운 타입을 만들어 변환하고 싶다면?
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
스프링은 확장 가능한 컨버터 인터페이스를 제공한다
org.springframework.core.convert.converter.Converter 인터페이스를 구현
ex) 문자 -> 숫자 변환
@Slf4j
public class StringToIntegerConverter implements Converter<String, Integer> {
@Override
public Integer convert(String source) {
log.info("convert source={}", source);
return Integer.valueOf(source);
}
}
Converter 기본 타입 컨버터
ConverterFactory 전체 클래스 계층 구조가 필요할 때
GenericConverter 정교한 구현, 대상 필드의 애노테이션 정보 사용 가능
ConditionalGenericConverter 특정 조건이 참인 경우에만 실행
참고
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#core-convert
컨버터를 직접 찾아 타입 변환에 사용하는 것은 불편하다
컨버전 서비스는 컨버터를 묶어 편리하게 사용할 수 있다
//ConversionService 인터페이스
package org.springframework.core.convert;
import org.springframework.lang.Nullable;
public interface ConversionService {
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor
targetType);
<T> T convert(@Nullable Object source, Class<T> targetType);
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,
TypeDescriptor targetType);
}
사용 예시
public class ConversionServiceTest {
@Test
void conversionService() {
//등록
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToIntegerConverter());
conversionService.addConverter(new IntegerToStringConverter());
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
//사용
assertThat(conversionService.convert("10", Integer.class)).isEqualTo(10);
assertThat(conversionService.convert(10, String.class)).isEqualTo("10");
IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
assertThat(ipPort).isEqualTo(new IpPort("127.0.0.1", 8080));
String ipPortString = conversionService.convert(new IpPort("127.0.0.1", 8080), String.class);
assertThat(ipPortString).isEqualTo("127.0.0.1:8080");
}
}
: 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 함
addFormatters() 로 컨버터 등록@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToIntegerConverter());
registry.addConverter(new IntegerToStringConverter());
registry.addConverter(new StringToIpPortConverter());
registry.addConverter(new IpPortToStringConverter());
}
}
💡 컨버터를 등록하지 않아도 스프링 내부에서 기본 컨버터를 제공
${{...}} , th:field
컨버전 서비스 자동 적용
Converter
Formatter
Formatter는 객체를 문자로 변경하고, 문자를 객체로 변경하는 두 가지 기능을 모두 수행
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> {
}
String print(T object, Locale locale) : 객체를 문자로 변경
T parse(String text, Locale locale) : 문자를 객체로 변경
참고
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#format
FormattingConversionService : 포맷터를 지원하는 컨버전 서비스
DefaultFormattingConversionService : FormattingConversionService 에 기본적인 통화, 숫자 관련 몇가지 기본 포맷터를 추가 제공
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
//컨버터 등록
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
//포맷터 등록
conversionService.addFormatter(new MyNumberFormatter());
//컨버터 사용
IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
assertThat(ipPort).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);
FormattingConversionService는 ConversionService 관련 기능을 상속 받아 컨버터, 포맷터 모두 등록 가능. 사용할 때는 ConversionService 가 제공하는 convert
를 사용
스프링 부트는 DefaultFormattingConversionService 를 상속 받은 WebConversionService를 내부에서 사용
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new MyNumberFormatter());
}
}
@NumberFormat
@DateTimeFormat
static class Form {
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
🔎 주의