스프링 타입 컨버터

이동건 (불꽃냥펀치)·2025년 2월 10일
0

스프링 타입 컨버터

문자를 숫자로 변환하거나 숫자를 문자로 변환해야하는 것처럼 애플리케이션을 개발하다 보면 타입을 변환해야 하는 경우가 많다.

타입변경의 예시

@RestController
 public class HelloController {
     @GetMapping("/hello-v1")
     public String helloV1(HttpServletRequest request) {
		String data = request.getParameter("data"); //문자 타입 조회 
		Integer intValue = Integer.valueOf(data); //숫자 타입으로 변경 
		System.out.println("intValue = " + intValue);
		return "ok";
	} 
}

String data = request.getParameter("data")
HTTP 요청 파라미터는 모두 문자로 처리된다. 따라서 요청 파라미터를 자바에서 다른 타입으로 변환해서 사용하고 싶으면 다음과 같이 숫자로 변환하는 과정을 거쳐야 한다.

스프링이 제공하는 타입변경

 @GetMapping("/hello-v2")
 public String helloV2(@RequestParam Integer data) {
     System.out.println("data = " + data);
     return "ok";
  }

http://localhost:8080/hello-v2?data=10
HTTP 쿼리 스트링으로 전달하는 data=10 부분에서 10은 숫자가 아닌 문자 10이다. 스프링이 제공하는 @RequestParam을 사용하면 문자 10을 숫자 10으로 편리하게 받을 수 있다.

스프링과 타입변환

개발자가 직접 하나씩 타입을 변경하는 것은 너무 번거롭다. 하지만 어쩔수 없이 수작업으로 Boolean타입을 숫자로 받아야 할 때도 있다.

 package org.springframework.core.convert.converter;
 public interface Converter<S, T> {
   T convert(S source);
}

스프링은 확장 가능ㄹ한 컨버터 인터페이스를 제공한다. 개발자는 스프링에 추가적인 타입 변환이 필요하면 이 컨버터 인터페이스를 구현해서 등록하면 된다.



타입 컨버터 _ Converter

문자를 숫자로 변경하는 Converter

 package hello.typeconverter.converter;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.convert.converter.Converter;
 @Slf4j
 public class StringToIntegerConverter implements Converter<String, Integer> {
     @Override
     public Integer convert(String source) {
         log.info("convert source={}", source);
         return Integer.valueOf(source);
     }
}

숫자를 문자로 변환하는 타입 Converter

 package hello.typeconverter.converter;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.convert.converter.Converter;
  @Slf4j
 public class IntegerToStringConverter implements Converter<Integer, String> {
     @Override
     public String convert(Integer source) {
         log.info("convert source={}", source);
         return String.valueOf(source);
     }
}

Converter test code 예시

 class ConverterTest {
     @Test
     void stringToInteger() {
         StringToIntegerConverter converter = new StringToIntegerConverter();
         Integer result = converter.convert("10");
         assertThat(result).isEqualTo(10);
	}
}



사용자 정의 타입 컨버터

IpPort

package hello.typeconverter.type;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 @Getter
 @EqualsAndHashCode
 public class IpPort {
     private String ip;
     private int port;
     public IpPort(String ip, int port) {
         this.ip = ip;
         this.port = port;
     }
}
  • 롬복의 @EqualsAndHashCode를 넣으면 모든 필드를 사용해서 equals(),hashcode()를 생성한다 따라서 모든 필드의 값이 같다면 a.equals(b)의 결과가 참이된다.

StringToIpPortConverter - 컨버터

package hello.typeconverter.converter;
 import hello.typeconverter.type.IpPort;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.convert.converter.Converter;
 @Slf4j
 public class StringToIpPortConverter implements Converter<String, IpPort> {
  @Override
     public IpPort convert(String source) {
         log.info("convert source={}", source);
         String[] split = source.split(":");
         String ip = split[0];
         int port = Integer.parseInt(split[1]);
         return new IpPort(ip, port);
     }
}

IpPortToStringConverter

package hello.typeconverter.converter;
 import hello.typeconverter.type.IpPort;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.core.convert.converter.Converter;
 @Slf4j
 public class IpPortToStringConverter implements Converter<IpPort, String> {
     @Override
     public String convert(IpPort source) {
         log.info("convert source={}", source);
         return source.getIp() + ":" + source.getPort();
     }
}
  • IpPort객체를 입력하면 127.0.0.1:8080 같은 문자를 반환한다.



컨버젼 서비스

스프링에서 제공하는 개별 Converter들을 모아놓고 그것들을 묶어서 편리하게 사용할 수 있는 기능을 제공하는 것을 컨버젼 서비스라한다.

컨버젼 서비스 테스트 코드

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");
     }
}



스프링에 Converter 적용하기

WebConfig - 컨버터 등록

 @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());
	} 
}
  • 스프링은 내부에서 conversionService를 제공한다. 우리는 WebMvcConfigurer가 제공하는 addFormatters()를 사용해서 추가하고 싶은 컨버터를 등록하면 된다



Formatter 만들기

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> {
 }

숫자 1000 을 문자 "1,000" 으로 그러니까, 1000 단위로 쉼표가 들어가는 포맷을 적용해보자. 그리고 그 반대도 처 리해주는 포맷터를 만들어보자.


 @Slf4j
 public class MyNumberFormatter implements Formatter<Number> {
     @Override
     public Number parse(String text, Locale locale) throws ParseException {
         log.info("text={}, locale={}", text, locale);
         NumberFormat format = NumberFormat.getInstance(locale);
         return format.parse(text);
}
     @Override
     public String print(Number object, Locale locale) {
         log.info("object={}, locale={}", object, locale);
         return NumberFormat.getInstance(locale).format(object);
     }
}

"1,000" 처럼 숫자 중간의 쉼표를 적용하려면 자바가 기본으로 제공하는 NumberFormat 객체를 사용하면 된다. 이 객체는 Locale 정보를 활용해서 나라별로 다른 숫자 포맷을 만들어준다.

  • parse()를 사용해서 문자를 숫자로 변경한다.
  • print()를 사용해서 객체를 문자로 변경한다.

Formatter 적용 코드

@Configuration
 public class WebConfig implements WebMvcConfigurer {
     @Override
     public void addFormatters(FormatterRegistry registry) {
         registry.addFormatter(new MyNumberFormatter());
     }
}








출처: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

profile
자바를 사랑합니다

0개의 댓글

관련 채용 정보