Spring MVC v2 - 스프링 타입 컨버터

Kwon Yongho·2023년 5월 8일
0

Spring-MVC-v2

목록 보기
12/13
post-thumbnail

스프링 타입 컨버터

  1. 스프링 타입 컨버터 소개
  2. 타입 컨버터 - Converter
  3. 컨버전 서비스 - ConversionService
  4. 스프링에 Converter 적용하기
  5. 뷰 템플릿에 컨버터 적용하기
  6. 포맷터 - Formatter
  7. 포맷터를 지원하는 컨버전 서비스
  8. 포맷터 적용하기
  9. 스프링이 제공하는 기본 포맷터

1. 스프링 타입 컨버터 소개

typeConverter 프로젝트를 새로 만들었다.

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

HelloController

package com.example.typeconverter.controller;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@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";
    }
}
  • HTTP 요청 파라미터는 모두 문자로 처리된다. 따라서 요청 파라미터를 자바에서 다른 타입으로 변환해서 사용하고 싶으면 다음과 같이 숫자 타입으로 변환하는 과정을 거쳐야 한다.
  • Integer intValue = Integer.valueOf(data)

스프링 MVC가 제공하는 @RequestParam

    @GetMapping("/hello-v2")
    public String helloV2(@RequestParam Integer data) {
        System.out.println("data = " + data);
        return "ok";
    }
  • @RequestParam을 사용하면 이 문자 10을 Integer 타입의 숫자 10으로 편리하게 받을 수 있다.

스프링의 타입 변환 적용 예

  • 스프링 MVC 요청 파라미터
    • @RequestParam, @ModelAttribute, @PathVariable
  • @Value 등으로 YML 정보 읽기
  • XML에 넣은 스프링 빈 정보를 변환
  • 뷰를 렌더링 할 때

만약 개발자가 새로운 타입을 만들어서 변환하고 싶으면 어떻게 하면 될까?

컨버터 인터페이스

public interface Converter<S, T> {
 T convert(S source);
}
  • 스프링은 확장 가능한 컨버터 인터페이스를 제공한다.
  • 개발자는 스프링에 추가적인 타입 변환이 필요하면 이 컨버터 인터페이스를 구현해서 등록하면 된다.
  • 예를 들어서 문자로 "true" 가 오면 Boolean타입으로 받고 싶으면 String -> Boolean 타입으로 변환되도록 컨버터 인터페이스를 만들어서 등록하고, 반대로 적용하고 싶으면 Boolean -> String 타입으로 변환되도록 컨버터를 추가로 만들어서 등록하면 된다.

2. 타입 컨버터 - Converter

타입 컨버터를 사용하려면 org.springframework.core.convert.converter.Converter 인터페이스를 구현하면 된다.

주의
Converter라는 이름의 인터페이스가 많으니 조심해야 한다.

가장 단순한 형태인 문자를 숫자로 바꾸는 타입 컨버터를 만들어보자.

StringToIntegerConverter

package com.example.typeconverter.converter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;

@Slf4j
public class StringToIntegerConverter implements Converter<String, Integer> { // 문자를 숫자로 converter

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

}

IntegerToStringConverter

package com.example.typeconverter.converter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;

@Slf4j
public class IntegerToStringConverter implements Converter<Integer, String> { // 숫자를 문자로 converter
    
    @Override
    public String convert(Integer source) {
        log.info("convert source={}", source);
        return String.valueOf(source);
    }
    
}

ConverterTest

package com.example.typeconverter.converter;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

public class ConverterTest {

    @Test
    void stringToInteger(){
        StringToIntegerConverter converter = new StringToIntegerConverter();
        Integer result = converter.convert("10"); // 문자 10
        Assertions.assertThat(result).isEqualTo(10); // 숫자 10
    }
    
    @Test
    void IntegerToString(){
        IntegerToStringConverter converter = new IntegerToStringConverter();
        String result = converter.convert(10); // 숫자 10
        Assertions.assertThat(result).isEqualTo("10"); // 문자 10
    }
}

IP, PORT를 입력하면 IpPort 객체로 변환하는 컨버터를 만들어보자.

IpPort

package com.example.typeconverter.type;

import lombok.EqualsAndHashCode;
import lombok.Getter;

@Getter
@EqualsAndHashCode // 모든 필드를 사용해서 equals, hashcode를 생성함
public class IpPort {
    
    private String ip;
    private int port;

    public IpPort(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

}

StringToIpPortConverter

package com.example.typeconverter.converter;

import com.example.typeconverter.type.IpPort;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;

@Slf4j
public class StringToIpPortConverter implements Converter<String, IpPort> { // 문자열을 IpPort 타입으로

    @Override
    public IpPort convert(String source) {
        log.info("conver source={}", source);
        // "127.0.0.1:8080"
        String[] split = source.split(":");
        String ip = split[0];
        int port = Integer.parseInt(split[1]);
        return new IpPort(ip,port);
    }

}

IpPortToStringConverter

package com.example.typeconverter.converter;

import com.example.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();
    }

}

테스트코드 추가

    @Test
    void stringToIpPort(){
        StringToIpPortConverter converter = new StringToIpPortConverter();
        IpPort result = converter.convert("127.0.0.1:8080");
        Assertions.assertThat(result).isEqualTo(new IpPort("127.0.0.1",8080));
    }
    
    @Test
    void ipPortToString(){
        IpPortToStringConverter converter = new IpPortToStringConverter();
        IpPort ipPort = new IpPort("127.0.0.1" , 8080);
        String result = converter.convert(ipPort);
        Assertions.assertThat(result).isEqualTo("127.0.0.1:8080");
    }

  • 이렇게 타입 컨버터를 하나하나 직접 사용하면, 개발자가 직접 컨버팅 하는 것과 큰 차이가 없다.
  • 타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 제공하는 역할을 하는 무언가가 필요하다.

3. 컨버전 서비스 - ConversionService

이렇게 타입 컨버터를 하나하나 직접 찾아서 타입 변환에 사용하는 것은 매우 불편하다. 그래서 스프링은 개별 컨버터를 모아두고 그것들을 묶어서 편리하게 사용할 수 있는 기능을 제공하는데, 이것이 바로 컨버전 서비스(ConversionService)이다.

ConversionService 인터페이스

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

ConversionServiceTest - 컨버전 서비스 테스트 코드

package com.example.typeconverter.converter;

import com.example.typeconverter.type.IpPort;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.support.DefaultConversionService;

import static org.assertj.core.api.Assertions.assertThat;

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

    }
}

  • DefaultConversionServiceConversionService 인터페이스를 구현했는데, 추가로 컨버터를
    등록하는 기능도 제공한다.

등록과 사용 분리

  • 컨버터를 등록할 때는 StringToIntegerConverter같은 타입 컨버터를 명확하게 알아야 한다.
  • 컨버터를 사용하는 입장에서는 타입 컨버터를 전혀 몰라도 된다.
  • 컨버전 서비스를 등록하는 부분과 사용하는 부분을 분리하고 의존관계 주입을 사용해야 한다.

인터페이스 분리 원칙 - ISP(Interface Segregation Principle)
인터페이스 분리 원칙은 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다.

DefaultConversionService는 다음 두 인터페이스를 구현했다.

  • ConversionService: 컨버터 사용에 초점
  • ConverterRegistry: 컨버터 등록에 초점

스프링은 내부에서 ConversionService를 사용해서 타입을 변환한다. 예를 들어서 앞서 살펴본 @RequestParam 같은 곳에서 이 기능을 사용해서 타입을 변환한다.

4. 스프링에 Converter 적용하기

WebConfig - 컨버터 등록

package com.example.typeconverter;

import com.example.typeconverter.converter.IntegerToStringConverter;
import com.example.typeconverter.converter.IpPortToStringConverter;
import com.example.typeconverter.converter.StringToIntegerConverter;
import com.example.typeconverter.converter.StringToIpPortConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@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()를 사용해서 추가하고 싶은 컨버터를 등록하면 된다.

localhost:8080/hello-v1?data=10 요청 시

StringToIntegerConverter : convert source=10
data = 10

StringToIntegerConverter를 등록하기 전에도 이 코드는 잘 수행되었다. 그것은 스프링이 내부에서 수 많은 기본 컨버터들을 제공하기 때문이다. 컨버터를 추가하면 추가한 컨버터가 기본 컨버터 보다 높은 우선순위를 가진다.

HelloController - 추가
(IpPort 변경)

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

localhost:8080/ip-port?ipPort=127.0.0.1:8080 요청

?ipPort=127.0.0.1:8080 쿼리 스트링이 @RequestParam IpPort ipPort에서 객체 타입으로 잘 변환 된 것을 확인할 수 있다.

5. 뷰 템플릿에 컨버터 적용하기

타임리프는 렌더링 시에 컨버터를 적용해서 렌더링 하는 방법을 편리하게 지원한다.

ConverterController

package com.example.typeconverter.controller;

import com.example.typeconverter.type.IpPort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ConverterController {
    
    @GetMapping("/converter-view")
    public String converterView(Model model) {
        model.addAttribute("number", 10000);
        model.addAttribute("ipPort", new IpPort("127.0.0.1", 8080));
        return "converter-view";
    }
    
}

converter-view.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li>${number}: <span th:text="${number}" ></span></li>
    <li>${{number}}: <span th:text="${{number}}" ></span></li>
    <li>${ipPort}: <span th:text="${ipPort}" ></span></li>
    <li>${{ipPort}}: <span th:text="${{ipPort}}" ></span></li>
</ul>
</body>
</html>

타임리프는 ${{...}}를 사용하면 자동으로 컨버전 서비스를 사용해서 변환된 결과를 출력해준다. 물론 스프링과 통합 되어서 스프링이 제공하는 컨버전 서비스를 사용하므로, 우리가 등록한 컨버터들을 사용할 수 있다.

변수 표현식: ${...}
컨버전 서비스 적용: ${{...}}


  • ${{number}}: 뷰 템플릿은 데이터를 문자로 출력한다. 따라서 컨버터를 적용하게 되면 Integer 타입인
    10000 을 String타입으로 변환하는 컨버터인 IntegerToStringConverter를 실행하게 된다.
  • ${{ipPort}}: 뷰 템플릿은 데이터를 문자로 출력한다. 따라서 컨버터를 적용하게 되면 IpPort 타입을
    String타입으로 변환해야 하므로 IpPortToStringConverter가 적용된다.

객체를 그냥 호출하면 객체.toString()이 호출된다.

폼에 적용하기
ConverterController - 코드 추가

 @GetMapping("/converter/edit")
    public String converterForm(Model model) {
        IpPort ipPort = new IpPort("127.0.0.1", 8080);
        Form form = new Form(ipPort);
        model.addAttribute("form", form);
        return "converter-form";
    }
    
    @PostMapping("/converter/edit")
    public String converterEdit(@ModelAttribute Form form, Model model) {
        IpPort ipPort = form.getIpPort();
        model.addAttribute("ipPort", ipPort);
        return "converter-view";
    }
    
    @Data
    static class Form {
        private IpPort ipPort;
        public Form(IpPort ipPort) {
            this.ipPort = ipPort;
        }
    }

converter-form.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form th:object="${form}" th:method="post">
    th:field <input type="text" th:field="*{ipPort}"><br/>
    th:value <input type="text" th:value="*{ipPort}">(보여주기 용도)<br/>
    <input type="submit"/>
</form>
</body>
</html>

타임리프의 th:field는 앞서 설명했듯이 id , name 를 출력하는 등 다양한 기능이 있는데, 여기에 컨버전 서비스도 함께 적용된다.

  • GET /converter/edit
    • th:field가 자동으로 컨버전 서비스를 적용해주어서 ${{ipPort}}처럼 적용이 되었다. 따라서 IpPort -> String으로 변환된다.
  • POST /converter/edit
    • @ModelAttribute를 사용해서 String -> IpPort로 변환된다.

6. 포맷터 - Formatter

개발자 입장에서는 문자를 다른 타입으로 변환하거나, 다른 타입을 문자로 변환하는 상황이 대부분이다.

웹 애플리케이션에서 객체를 문자로, 문자를 객체로 변환하는 예

  • 화면에 숫자를 출력해야 하는데, Integer -> String 출력 시점에 숫자 1000 문자 "1,000" 이렇게 1000 단위에 쉼표를 넣어서 출력하거나, 또는 "1,000" 라는 문자를 1000 이라는 숫자로 변경해야 한다.
  • 날짜 객체를 문자인 "2021-01-01 10:50:11"와 같이 출력하거나 또는 그 반대의 상황

이렇게 객체를 특정한 포멧에 맞추어 문자로 출력하거나 또는 그 반대의 역할을 하는 것에 특화된 기능이 바로 포맷터(Formatter)이다. 포맷터는 컨버터의 특별한 버전으로 이해하면 된다.

Converter vs Formatter

  • Converter는 범용(객체 객체)
  • Formatter 는 문자에 특화(객체 문자, 문자 객체) + 현지화(Locale)

포맷터(Formatter)는 객체를 문자로 변경하고, 문자를 객체로 변경하는 두 가지 기능을 모두 수행한다.

  • String print(T object, Locale locale): 객체를 문자로 변경한다.
  • T parse(String text, Locale locale): 문자를 객체로 변경한다.

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

MyNumberFormatter

package com.example.typeconverter.formatter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.format.Formatter;

import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

@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);
        // 1000 -> "1,000"
        return NumberFormat.getInstance(locale).format(object);
    }
}
  • NumberFormat객체를 사용하면 된다. 이 객체는 Locale 정보를 활용해서 나라별로 다른 숫자 포맷을 만들어준다.

MyNumberFormatterTest 테스트 코드

package com.example.typeconverter.formatter;

import org.junit.jupiter.api.Test;

import java.text.ParseException;
import java.util.Locale;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

class MyNumberFormatterTest {

    MyNumberFormatter formatter = new MyNumberFormatter();
    @Test
    void parse() throws ParseException {
        Number result = formatter.parse("1,000", Locale.KOREA);
        assertThat(result).isEqualTo(1000L); //Long 타입 주의
    }
    @Test
    void print() {
        String result = formatter.print(1000, Locale.KOREA);
        assertThat(result).isEqualTo("1,000");
    }
}

스프링은 다양한 방식의 포멧터를 제공한다.
자세한 내용은 공식 문서를 참고
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#format

7. 포맷터를 지원하는 컨버전 서비스

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

FormattingConversionServiceTest로 확인하기

package com.example.typeconverter.formatter;

import com.example.typeconverter.converter.IpPortToStringConverter;
import com.example.typeconverter.converter.StringToIpPortConverter;
import com.example.typeconverter.type.IpPort;
import org.junit.jupiter.api.Test;
import org.springframework.format.support.DefaultFormattingConversionService;

import static org.assertj.core.api.Assertions.assertThat;

public class FormattingConversionServiceTest {
    @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);
    }
}

FormattingConversionServiceConversionService 관련 기능을 상속받기 때문에 결과적으로 컨버터도 포맷터도 모두 등록할 수 있다. 그리고 사용할 때는 ConversionService가 제공하는 convert를 사용하면 된다.

8. 포맷터 적용하기

WebConfig 수정

package com.example.typeconverter;

import com.example.typeconverter.converter.IntegerToStringConverter;
import com.example.typeconverter.converter.IpPortToStringConverter;
import com.example.typeconverter.converter.StringToIntegerConverter;
import com.example.typeconverter.converter.StringToIpPortConverter;
import com.example.typeconverter.formatter.MyNumberFormatter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

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

localhost:8080/converter-view 요청 시

  • 컨버전 서비스를 적용한 결과 MyNumberFormatter가 적용되어서 10,000 문자가 출력된 것을 확인할 수 있다.

9. 스프링이 제공하는 기본 포맷터

  • 스프링은 자바에서 기본으로 제공하는 타입들에 대해 수 많은 포맷터를 기본으로 제공한다.

  • IDE에서 Formatter인터페이스의 구현 클래스를 찾아보면 수 많은 날짜나 시간 관련 포맷터가 제공되는 것을 확인할 수 있다.

  • 포맷터는 기본 형식이 지정되어 있기 때문에, 객체의 각 필드마다 다른 형식으로 포맷을 지정하기는 어렵다.

  • 스프링은 이런 문제를 해결하기 위해 애노테이션 기반으로 원하는 형식을 지정해서 사용할 수 있는 매우 유용한 포맷터 두 가지를 기본으로 제공한다.

  • @NumberFormat: 숫자 관련 형식 지정 포맷터 사용, NumberFormatAnnotationFormatterFactory

  • @DateTimeFormat: 날짜 관련 형식 지정 포맷터 사용, Jsr310DateTimeFormatAnnotationFormatterFactor

FormatterController

package com.example.typeconverter.controller;

import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import java.time.LocalDateTime;

@Controller
public class FormatterController {

    @GetMapping("/formatter/edit")
    public String formatterForm(Model model) {
        Form form = new Form();
        form.setNumber(10000);
        form.setLocalDateTime(LocalDateTime.now());
        model.addAttribute("form", form);
        return "formatter-form";
    }

    @PostMapping("/formatter/edit")
    public String formatterEdit(@ModelAttribute Form form) {
        return "formatter-view";
    }

    @Data
    static class Form {

        // 스프링 제공 애노테이션 포맷터
        @NumberFormat(pattern = "###,###")
        private Integer number;

        // 스프링 제공 애노테이션 포맷터
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime localDateTime;

    }
}

localhost:8080/formatter/edit 요청 시

  • 애노테이션만으로 포맷터가 적용 된 것을 확인 할 수 있다.

주의

  • 메시지 컨버터(HttpMessageConverter)에는 컨버전 서비스가 적용되지 않는다.
  • 객체를 JSON으로 변환할 때 메시지 컨버터를 사용하면서 이 부분을 많이 오해하는데, HttpMessageConverter의 역할은 HTTP 메시지 바디의 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력하는 것이다.
  • 예를 들어서 JSON을 객체로 변환하는 메시지 컨버터는 내부에서 Jackson같은 라이브러리를 사용한다. 객체를 JSON으로 변환한다면 그 결과는 이 라이브러리에 달린 것이다. 따라서 JSON 결과로 만들어지는 숫자나 날짜 포맷을 변경하고 싶으면 해당 라이브러리가 제공하는 설정을 통해서 포맷을 지정해야 한다.

참고
김영한: 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술(인프런)
Github - https://github.com/b2b2004/Spring_MVC

0개의 댓글