반응형

Converter 란?

  • 객체를 다른 객체로 변환하는 기능
  • 문자 <-> 숫자와 같은 변환들도 가능하고 객체끼리의 변환도 가능

Formatter 란?

  • Formatter은 Converter와 비슷한 개념이지만 Converter은 객체 -> 객체에 사용된다면 Formatter은 객체 -> 문자, 문자 -> 객체에 특화되있음
    • ex) 1000 -> "1,000" , LocalDateTime -> "yyyy-MM-dd HH:mm:ss" 같은 변환에 사용하면 유용
  • 현지화 정보 (Locale)를 사용할 수 있음

Converter 예제

  • URL 파라미터에 들어오는 값은 항상 String 타입인데, 이를 내가 만든 IpPort 타입으로 변환하는 Converter 예제
  • 파라미터로 "127.0.0.1:8080"가 들어오면 ip = "127.0.0.1", port = 8080으로 변환하는 예제

IpPort

@Data
@AllArgsConstructor
public class IpPort {

    private String ip;
    private int port;
}

StringToIpPortConverter

  • Converter<String, IpPort> : String을 IpPort 타입으로 convert 한다는 의미
public class StringToIpPortConverter implements Converter<String, IpPort> {

    @Override
    public IpPort convert(String source) {
        String[] splitSource = source.split(":");

        String ip = source.split(":")[0];
        int port = Integer.valueOf(source.split(":")[1]);

        return new IpPort(ip, port);
    }
}

Controller

  • 파라미터를 받을때 String 타입으로 받음
  • StringToIpPortConverter 객체를 받아와 convert 메소드를 직접 사용해서 변환해도 되지만 conversionService를 이용해 변환할 수 있음
  • conversionService를 이용하면 여러개의 converter을 한번에 add해놓고 사용할 때는 사용만 하면 됨
@ResponseBody
@GetMapping("/string-to-ip-port-v1")
public IpPort stringToIpPortV1(@RequestParam String str) {
    DefaultConversionService conversionService = new DefaultConversionService();
    conversionService.addConverter(new StringToIpPortConverter());

    IpPort ipPort = conversionService.convert(str, IpPort.class);
    return ipPort;
}

결과

Converter 예제 2 - addFormatters 사용

  • 위의 방식은 conversionService를 등록하고 매번 갖다 쓰는 방식
  • 만약 이 Converter을 여러번 사용한다면 WebMvcConfigurer에 등록되어 있는 addFormatters를 통해 한 번에 등록하고 자동으로 변환하는 방식

WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToIpPortConverter());
    }
}

Controller

  • URL 파라미터는 String 타입인데 여기서는 IpPort 타입으로 받음
    • 위에서 등록한 StringToIpPortConverter가 이를 인식하고 String 타입의 입력을 자동으로 IpPort 타입으로 변환해줌
@ResponseBody
@GetMapping("/string-to-ip-port-v2")
public IpPort stringToIpPortV2(@RequestParam IpPort ipPort) {
    return ipPort;
}

결과

Thymeleaf에서의 Converter 사용 예제

IpPortToStringConverter

  • 위의 예제와 반대로 IpPort를 String으로 변환해주는 Converter
  • 아래와 같이 작성 후 addFormatters에 같은 방식으로 등록해줘야 함
public class IpPortToStringConverter implements Converter<IpPort, String> {

    @Override
    public String convert(IpPort source) {
        return source.getIp() + ":" + source.getPort();
    }
}

Controller

  • model에 IpPort 객체를 담아 전송
@GetMapping("/ip-port-to-string")
public String ipPortToString(Model model) {
    model.addAttribute("ipPort", new IpPort("127.0.0.1", 8000));
    return "converterPage";
}

converterPage.html

  • Thymeleaf에서 기본적으로 모델 값을 받을때는 { } 를 사용
  • 이 때, {{ }} 를 사용하면 객체에 맞는 Converter을 적용해서 출력
<ul>
    <li>${ipPort} : <span th:text="${ipPort}"></span></li>
    <li>${{ipPort}} : <span th:text="${{ipPort}}"></span></li>
</ul>

결과

  • thymeleaf form에서는 th:field가 자동으로 converter을 적용해 줌
    • 적용하기 싫으면 th:value 사용

Formatter 예제

MyNumberFormatter

  • 1000 -> "1,000" 으로 변환해주는 기능
  • 여기서 locale 는 현지화를 뜻하는데, 한국에서 실행하기 때문에 ko 이고, 한국 방식은 1000 -> "1,000"
public class MyNumberFormatter implements Formatter<Number> {
    @Override
    public Number parse(String text, Locale locale) throws ParseException {
        // "1,000" -> 1000
        NumberFormat format = NumberFormat.getInstance(locale);
        return format.parse(text);
    }

    @Override
    public String print(Number object, Locale locale) {
        // 1000 -> "1,000"
        NumberFormat instance = NumberFormat.getInstance(locale);
        return instance.format(object);
    }
}

WebConfig

  • converter은 addConverter을 해준것과 비슷하게 formatter은 addFormatter을 해주면 됨
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new MyNumberFormatter());
    }
}

Controller

  • 화면으로 숫자 10000000을 넘겨줌 => 화면에선 10,000,000으로 출력
@GetMapping("/formatter-page")
public String formatterPage(Model model) {
    model.addAttribute("number", 10000000);
    return "formatterPage";
}

formatterPage.html

  • converter와 같이 {{}}를 사용함으로써, formatting이 적용됨
  • form에서도 마찬가지로 th:field가 자동으로 해주고, 적용하기 싫다면 th:value 사용
<ul>
    <li>${number} : <span th:text="${number}"></span></li>
    <li>${{number}} : <span th:text="${{number}}"></span></li>
</ul>

결과

특정 Object에서 변수에 어노테이션을 적용해 Formatter 적용 예제

Product

@Data
@AllArgsConstructor
public class Product {

    private String name;

    @NumberFormat(pattern = "###,###원")
    private int price;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime registerDate;
}

Controller

@GetMapping("/formatter-page")
public String formatterPage(Model model) {
    model.addAttribute("product", new Product("가방", 1000000, LocalDateTime.now()));
    return "formatterPage";
}

formatterPage.html

  • 상품명에는 Formatter 적용 X
  • 가격과 등록일에 적용한 Formatter가 적용되기 위해 {{ }} 사용
<ul>
    <li>상품명 : <span th:text="${product.name}"></span></li>
    <li>가격 : <span th:text="${{product.price}}"></span></li>
    <li>등록일 : <span th:text="${{product.registerDate}}"></span></li>
</ul>

결과

반응형

↓ 클릭시 이동

복사했습니다!