org.springframework.core.convert.converter.Converter
인터페이스를 구현IpPort객체 -> String
@Slf4j
public class IpPortToStringConverter implements Converter<IpPort,String> {
@Override
public String convert(IpPort source) {
log.info("convert source={}",source);
//IpPort 객체 -> "127.0.0.1:8080"
return source.getIp()+":"+source.getPort();
}
}
String -> IpPort 객체
@Slf4j
public class StringToIpPortConverter implements Converter<String, IpPort> {
@Override
public IpPort convert(String source) {
log.info("convert source={}",source);
//"127.0.0.1:8080" -> IpPort 객체
String[] split = source.split(":");
String ip=split[0];
int port=Integer.parseInt(split[1]);
return new IpPort(ip,port);
}
}
테스트 코드
@Test
void stringToIpPort(){
IpPortToStringConverter converter = new IpPortToStringConverter();
IpPort source = new IpPort("127.0.0.1", 8080);
String result = converter.convert(source);
assertThat(result).isEqualTo("127.0.0.1:8080");
}
@Test
void ipPortToString(){
StringToIpPortConverter converter = new StringToIpPortConverter();
String source="127.0.0.1:8080";
IpPort result = converter.convert(source);
assertThat(result).isEqualTo(new IpPort("127.0.0.1", 8080));
//롬복의 @EqualsAndHashCode 를 넣으면
//모든 필드를 사용해서 equals() , hashcode() 를 생성
//따라서 모든 필드의 값이 같다면 a.equals(b) 의 결과가 참 (IpPort에 적용되어있음)
@Test
void conversionService(){
//등록 (사용할 컨버터들을 컨버전 서비스에 등록)
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToIntegerConverter());
conversionService.addConverter(new IntegerToStringConverter());
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
//사용 conversionService.convert(데이터, 변환하고싶은 데이터 타입)
assertThat(conversionService.convert("10", Integer.class)).isEqualTo(10);
assertThat(conversionService.convert(10, String.class)).isEqualTo("10");
IpPort result = conversionService.convert("127.0.0.1:8080", IpPort.class);
assertThat(result).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");
}
컨버터 등록
@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());
}
}
WebMvcConfigurer
가 제공하는 addFormatters()
를 사용해서 추가하고 싶은 컨버터를 등록ConversionService
에 컨버터를 추가실행
@GetMapping("/ip-port")
public String ipPort(@RequestParam IpPort ipPort){
System.out.println("ipPort IP = " + ipPort.getIp());
System.out.println("ipPort PORT = " + ipPort.getPort());
return "ok";
}
@RequestParam
은 @RequestParam
을 처리하는 ArgumentResolver
에서 ConversionService
를 사용해서 타입을 변환@RequestParam
, @ModelAttribute
, @PathVariable
에서 다 적용됨${...}
${{...}}
@Slf4j
public class MyNumberFormatter implements Formatter<Number> {
//문자를 객체로 변경
@Override
public Number parse(String text, Locale locale) throws ParseException {
log.info("text={}, locale={}",text,locale);
//"1,000" -> 1000
NumberFormat format = NumberFormat.getInstance(locale);
//이미 구현되어 있는 것을 사용
return format.parse(text);
}
// 객체를 문자로 변경
@Override
public String print(Number object, Locale locale) {
log.info("object={}, locale={}",object,locale);
NumberFormat instance = NumberFormat.getInstance(locale);
return instance.format(object);
}
}
NumberFormat
객체를 사용하면 Locale 정보를 활용해서 나라별로 다른 숫자 포맷을 만들어줌parse()
의 결과는 Long @Test
void 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
관련 기능을 상속받기 때문에 결과적으로 컨버터도 포맷터도 모두 등록할 수 있음@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());
//포맷터 추가
registry.addFormatter(new MyNumberFormatter());
}
}
스프링은 자바에서 기본으로 제공하는 타입들에 대해 수 많은 포맷터를 기본으로 제공
@Data
static class Form{
@NumberFormat(pattern = "###,###") //내가 원하는 형식 지정
private Integer number;
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
@NumberFormat
: 숫자 관련 형식 지정 포맷터 사용@DateTimeFormat
: 날짜 관련 형식 지정 포맷터 사용주의
- 메시지 컨버터(HttpMessageConverter)에는 컨버전 서비스가 적용되지 않음
- HttpMessageConverter의 역할은 단지 HTTP 메시지 바디의 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력하는 것
- 컨버전 서비스는
@RequestParam
,@ModelAttribute
,@PathVariable
, 뷰 템플릿 등에서 사용할 수 있음- 메시지 컨버터는 컨버전 서비스와 전혀 관계가 없음