타입 컨버터

강한친구·2022년 6월 23일
0

Spring

목록 보기
27/27
post-thumbnail

문자의 변환

URL경로는 항상 문자이다.

parameter로 data=10이 들어온다면, 이는 String형태이고, 이를 숫자로 받으려면 유저가 내부에서 변환을 해야한다.

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

혹은 RequestParam으로 변환할 수도 있다.

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

이는 스프링이 컨버터 기능을 지원해서 자동변환 해주기 때문이다. 만약 개발자가 자신이 타입을 만들어서 변환하고 싶다면 어떻게 해야할까?

이때를 위해서 컨버터 인테페이스가 존재한다.

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

직접 Int/String Converter 구현

@Slf4j
public class StringToIntegerConverter implements Converter<String, Integer> {

    @Override
    public Integer convert(String source) {
        log.info("convert source={}", source);
        return Integer.valueOf(source);
    }
}
@Slf4j
public class IntegerToStringConverter implements Converter<Integer, String> {

    @Override
    public String convert(Integer source) {
        log.info("convert source={}", source);
        return String.valueOf(source);
    }
}

이렇게 Converter를 받아서 사용할 수 있다.

IpPort 컨버팅

IpPort라는 내가 직접 만든 Type을 String을 변환 할 수 있다.

> Converter 기본 타입 컨버터
> ConverterFactory 전체 클래스 계층 구조가 필요할 때
> GenericConverter 정교한 구현, 대상 필드의 애노테이션 정보 사용 가능
> ConditionalGenericConverter 특정 조건이 참인 경우에만 실행

컨버터는 이처럼 다양한 기능을 제공한다.
하지만 이를 직접 사용하는건 불편하다. 따라서 이를 묶어서 사용하는 Conversion 서비스에 대해 알아보겠다.

Conversion Service

DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToIntegerConverter());
conversionService.addConverter(new IntegerToStringConverter());
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());

이런식으로 컨버전 서비스를 등록해놓고

conversionService.convert("10",Integer.class)

이런식으로 사용하면 알아서 conversionService가 찾아서 해결해준다.

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

이제 아까만든 controller를 써보면

이렇게 잘 작동되는것을 알 수 있다. 하지만 이는 아까도 잘 작동했다. 이는 스프링이 기본적으로 컨버터를 제공해주기 때문이다.

직접 만든 IpPort 변환기

http://localhost:8080/ip-port?ipPort=127.0.0.1:8080

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

이 컨트롤러를 실행해보면

이렇게 잘 작동한다.

또한 View에서의 컨버팅도 잘 작동한다.

Formatter

컨버터는 입력과 출력 타입에 제한이 없는 변환기능을 제공한다.
만약 1000 이라는 문자를 1,000이라는 현금 단위로 바꾸거나, 날짜를 포맷에 맞춰서 출력할 때 어떻게 해야할까?

이때 사용하는 기능이 Formatter이다.
포매터에는 출력담당의 프린터와 변환담당의 파서 두 기능이 있다. 이를 모두 구현해야한다.

@Slf4j
public class MyNumberFormatter implements Formatter {

    @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(Object object, Locale locale) {
        log.info("object={}, locale={}", object, locale);
        return NumberFormat.getInstance(locale).format(object);
    }
}

각 로케일에 맞춰서 미리 스프링이 구현해둔 방식으로 변환해준다.

컨버전서비스에 등록하기

FormattingConversionService 는 포맷터를 지원하는 컨버전 서비스이다.
DefaultFormattingConversionService 는 FormattingConversionService 에 기본적인 통화, 숫자 관련 몇가지 기본 포맷터를 추가해서 제공한다.

        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        
        conversionService.addConverter(new StringToIpPortConverter());
        conversionService.addConverter(new IpPortToStringConverter());
        
        conversionService.addFormatter(new MyNumberFormatter());

DefaultConversionService는 포매터는 물론 컨버터도 지원한다. 따라서 통합해서 사용하면 된다.

        registry.addConverter(new StringToIpPortConverter());
        registry.addConverter(new IpPortToStringConverter());
        registry.addFormatter(new MyNumberFormatter());

WebConfig에는 이런식으로 추가하면, 정상적으로 NumberFormatter가 작동한다.

스프링 기본 제공 Formatter

스프링은 많은 기본 포메터를 제공하고, 동시에 어노테이션으로 포맷을 지정해줄 수 있는 포메터를 제공해준다.

	@Data
    static class Form {
        @NumberFormat(pattern = "###,###")
        private Integer number;
        
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime localDateTime;
    }

annotation으로 값을 주면, 해당 양식에 맞춰서 formatting이 작동하게 된다.


0개의 댓글