Back-End (Web)/Spring

Formatter

JABHACK 2025. 1. 11. 11:20

Formatter

📌 주로 사용자 지정 포맷을 적용해 데이터 변환을 처리할 때 사용된다. FormatterConversionService와 비슷한 목적을 가지지만 문자열을 객체로 변환하거나 객체를 문자열로 변환하는 과정에서 포맷팅을 세밀하게 제어할 수 있다.

  • 객체를 특정한 포맷에 맞춰서 문자로 출력하는 기능에 특화된것이 Fomatter이다.
  • Converter보다 조금 더 세부적인 기능이라고 생각하면 된다.
더보기

Spring에서 FormatterConverter는 모두 데이터 변환과 관련이 있지만, 주요 사용 목적기능에서 차이가 있습니다. 이 둘은 서로 보완적으로 사용되며, 특정 상황에서 더 적합한 도구를 선택할 수 있습니다.


Formatter와 Converter의 차이

특징 Formatter Converter
주요 목적 데이터 변환과 포맷팅(formatting) 지원. 단순히 타입 변환에 집중.
양방향 변환 String ↔ Object 형태로 양방향 변환 지원. 한 방향으로만(Source → Target) 변환 가능.
대상 데이터 주로 사용자 입력 데이터를 처리하거나 포맷팅이 필요한 데이터. 데이터 타입 간 변환(예: String → Integer, String → Enum).
인터페이스 구조 Formatter<T> (포맷 변환 및 역변환 메서드 포함). Converter<S, T> (단일 변환 메서드만 포함).
사용 위치 사용자 입력 데이터(폼 데이터, 요청 파라미터 등) 처리. 내부적으로 데이터 바인딩 및 단순 변환 처리.
Spring 사용 방식 FormattingConversionService를 통해 등록 및 관리. ConversionService를 통해 등록 및 관리.

Formatter

Formatter는 주로 데이터를 특정 형식(포맷)으로 변환하거나, 문자열 데이터를 객체로 역변환하는 데 사용됩니다.

인터페이스 정의

public interface Formatter<T> {
    String print(T object, Locale locale);   // 객체 → 문자열 (포맷팅)
    T parse(String text, Locale locale) throws ParseException; // 문자열 → 객체 (역변환)
}

Formatter 사용 예: String ↔ LocalDate

public class LocalDateFormatter implements Formatter<LocalDate> {

    @Override
    public LocalDate parse(String text, Locale locale) throws ParseException {
        return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    @Override
    public String print(LocalDate object, Locale locale) {
        return object.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
}

Formatter 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

사용 예

컨트롤러 메서드에서 LocalDate를 자동 변환:

@GetMapping("/date")
public String getDate(@RequestParam LocalDate date) {
    return "Formatted Date: " + date.toString();
}

요청:

GET /date?date=2023-12-25

Converter

Converter는 단순히 하나의 데이터 타입을 다른 데이터 타입으로 변환합니다.

인터페이스 정의

public interface Converter<S, T> {
    T convert(S source); // 소스 타입 → 대상 타입
}

Converter 사용 예: String → Integer

public class StringToIntegerConverter implements Converter<String, Integer> {

    @Override
    public Integer convert(String source) {
        return Integer.valueOf(source);
    }
}

Converter 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

사용 예

컨트롤러 메서드에서 Integer를 자동 변환:

@GetMapping("/number")
public String getNumber(@RequestParam Integer number) {
    return "Number: " + number;
}

요청:

GET /number?number=123

Formatter와 Converter의 사용 사례 비교

기능 Formatter Converter
날짜 변환 2023-12-25 ↔ LocalDate 지원하지 않음 (포맷팅 기능 없음).
Enum 변환 ACTIVE ↔ Status.ACTIVE String → Status.ACTIVE.
사용자 입력 처리 사용자 입력 데이터를 읽어 포맷팅. 단순 데이터 변환 작업.
예제 요청 파라미터 GET /date?date=2023-12-25 GET /number?number=123.

Converter와 Formatter의 동작 구조

  1. Converter:
    • 입력 데이터가 단순히 변환되기만 하면 되는 경우 사용.
    • : 쿼리 파라미터 123 → Integer.
  2. Formatter:
    • 사용자 입력 데이터가 특정 형식에 따라 변환되고 역변환이 필요한 경우 사용.
    • : yyyy-MM-dd → LocalDate.

결론

  • Converter: 단순히 데이터 타입을 변환할 때 사용.
    • 비유: 변환기. 한 단위를 다른 단위로 바꾸는 도구.
  • Formatter: 데이터 변환과 동시에 포맷팅이 필요한 경우 사용.
    • 비유: 포맷터. 데이터를 사람이 읽기 좋은 형식으로 변환하는 도구.

선택 기준:

  • 단순 타입 변환: Converter 사용.
  • 포맷팅과 역변환 모두 필요: Formatter 사용.
  • Locale
    • 지역 및 언어 정보를 나타내는 객체.
      • 언어코드 en, ko
      • 국가코드 US, KR
    • 특정 지역 및 언어에 대한 정보를 제공하여 국제화 및 지역화 기능을 지원한다.
    • 국제화
      • Locale 정보에 따라서 한글을 보여줄지 영문을 보여줄지 선택할 수 있다.

 

Formatter Interface

  • Printer, Parser 상속
  • 객체를 문자로 변환하고 문자를 객체로 변환하는 두가지 기능을 모두 가지고 있다.
  • Printer

Object를 String으로 변환한다.

 

Parser

String을 Object로 변환한다.

 

 

Formatter 적용

@Slf4j
public class PriceFormatter implements Formatter<Number> {
	
	@Override
  public Number parse(String text, Locale locale) throws ParseException {
    log.info("text = {}, locale={}", text, locale);
		
		// 변환 로직
		// NumberFormat이 제공하는 기능
		NumberFormat format = NumberFormat.getInstance(locale);
		// "10,000" -> 10000L
		return format.parse(text);
  }

  @Override
  public String print(Number object, Locale locale) {
			log.info("object = {}, locale = {}", object, locale);
			// 10000L -> "10,000"
      return NumberFormat.getInstance(locale).format(object);
  }
	
}

 

Number

  • Integer, Long, Double 등의 부모 클래스
class PriceFormatterTest {

		PriceFormatter formatter = new PriceFormatter();

    @Test
    void parse() throws ParseException {
        // given, when
        Number result = formatter.parse("1,000", Locale.KOREA);

        // then
        // parse 결과는 Long
        Assertions.assertThat(result).isEqualTo(1000L);
    }

    @Test
    void print() {
        // given, when
        String result = formatter.print(1000, Locale.KOREA);

        // then
        Assertions.assertThat(result).isEqualTo("1,000");
    }
}

 

 

 

Spring Formatter

📌 Spring의 Formatter는 문자열 데이터를 특정 객체로 변환하거나, 객체를 특정 문자열 형식으로 변환(포맷팅)하는 데 사용되는 인터페이스입니다. 데이터 포맷팅과 역변환을 쉽게 처리할 수 있도록 Spring에서 제공됩니다

 

 

FormattingConversionService

📌 ConversionServiceFormatter를 결합한 구현체로 타입 변환과 포맷팅이 필요한 모든 작업을 한 곳에서 수행할 수 있도록 설계되어 있어서 다양한 타입의 변환과 포맷팅을 쉽게 적용할 수 있다.

  • 어댑터 패턴을 사용하여 Formatter가 Converter처럼 동작하도록 만들어준다.

 

DefaultFormattingConversionService

📌 FormattingConversionService + 통화, 숫자관련 Formatter를 추가한것

public class FormattingConversionServiceTest {

    @Test
    void formattingConversionService() {

        // given
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();

        // Converter 등록
        conversionService.addConverter(new StringToPersonConverter());
        conversionService.addConverter(new PersonToStringConverter());
        // Formatter 등록
        conversionService.addFormatter(new PriceFormatter());

        // when
        String result = conversionService.convert(10000, String.class);

        // then
        Assertions.assertThat(result).isEqualTo("10,000");

    }

}
  • ConversionService가 제공하는 convert()를 사용하면 된다.

 

SpringBoot의 기능

📌 SpringBoot는 기본적으로 WebConversionService를 사용한다.

  • DefaultFormattingConversionService 상속

 

 

Spring이 제공하는 Formatter

📌 Spring은 어노테이션 기반으로 원하는 형식Formatter를 사용할 수 있도록 기능을 제공한다.

  • Annotation
    • DTO 필드들에 적용 가능
    1. @NumberFormat
      • 숫자 관련 지정 Formatter 사용
      • NumberFormatAnnotationFormatterFactory
    2. @DateTimeFormat
      • 날짜 관련 지정 Formatter 사용
      • Jsr310DateTimeFormatAnnotationFormatterFactory
 

Spring Field Formatting :: Spring Framework

As discussed in the previous section, core.convert is a general-purpose type conversion system. It provides a unified ConversionService API as well as a strongly typed Converter SPI for implementing conversion logic from one type to another. A Spring conta

docs.spring.io

 

 

 

'Back-End (Web) > Spring' 카테고리의 다른 글

fetch join  (1) 2025.01.21
API 예외처리  (0) 2025.01.19
TypeConverter  (0) 2025.01.10
HttpMessageConverter  (0) 2025.01.09
ArgumentResolver  (0) 2025.01.08