MVC2 10th Step

최보현·2022년 8월 19일
0

MVC

목록 보기
17/18
post-thumbnail

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - sec10
출처 : 스프링 MVC 2편

컨버터 & 포맷터

What is Converter?

약간 우리가 살다보면 문자를 숫자로 아니면 그 역순으로 바꿔야하는 순간이 오는데 그걸 용이하게 해주는 친구라고 보면 됨 (굳이 문자나 숫자로만 국한되지는 않음)
예를 들어서 url에 파라미터로 들어오는 숫자들이 정말 찐 숫자같아 보이겠지만 원래는 String임 "10"이라는 뜻 => 근데 우리는 편하게 숫자 10을 받음
어케 가능하지? 스프링이 중간에서 타입 변환을 해주었거든

스프링의 타입 변환 적용 예

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

스프링과 타입 변환

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

스프링은 확장 가능한 컨버터 인터페이스를 제공함
개발자는 스프링에 추가적인 타입 변환이 필요하면 이 컨버터 인터페이스를 구현해서 등록하면 됨(모든 타입에 적용 가능)

타입 컨버터 - Converter

타입 컨버터를 사용하려면 org.springframework.core.convert.converter.Converter 인터페이스를 구현하면 됨
Converter : 기본 타입 컨버터
ConverterFactory : 전체 클래스 계층 구조가 필요할 때
GenericConverter : 정교한 구현, 대상 필드의 애노테이션 정보 사용 가능
ConditionalGenericConverter : 특정 조건이 참인 경우에만 실행

컨버전 서비스 - ConversionService

개별 컨버터를 모아두고 그것들을 묶어서 편리하게 사용할 수 있는 기능 제공

package org.springframework.core.convert;
import org.springframework.lang.Nullable;

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

컨버전 서비스 인터페이스는 단순히 컨버팅이 가능한가? 확인하는 기능과, 컨버팅 기능 제공

DefaultConversionService 는 ConversionService 인터페이스를 구현했는데, 추가로 컨버터를 등록하는 기능도 제공

등록과 사용 분리
컨버터를 등록할 때는 StringToIntegerConverter 같은 타입 컨버터를 명확하게 알아야 하지만, 컨버터를 사용하는 입장에서는 타입 컨버터를 전혀 몰라도 됨
타입 컨버터들은 모두 컨버전 서비스 내부에 숨어서 제공됨 => 타입 변환을 원하는 사용자는 컨버전 서비스 인터페이스에만 의존하면 됨
컨버전 서비스를 등록하는 부분과 사용하는 부분을 분리하고 의존관계 주입을 사용해야 함

컨버전 서비스 사용
Integer value = conversionService.convert("10", Integer.class)

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

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

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

인터페이스를 분리하면 컨버터를 사용하는 클라이언트와 컨버터를 등록하고 관리하는 클라이언트의 관심사를 명확하게 분리할 수 있음! 특히 컨버터를 사용하는 클라이언트는 ConversionService 만 의존하면 되므로, 컨버터를 어떻게 등록하고 관리하는지는 전혀 몰라도 됨
결과적으로 컨버터를 사용하는 클라이언트는 꼭 필요한 메서드만 알게됨

컨버터 적용
스프링은 내부에서 ConversionService 를 제공 => WebMvcConfigurer 가 제공하는 addFormatters() 를 사용해서 추가하고 싶은 컨버터를 등록하면 됨
이렇게 하면 스프링은 내부에서 사용하는 ConversionService 에 컨버터를 추가

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

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

<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>
  • 변수 표현식 : ${...}
  • 컨버전 서비스 적용 : ${{...}}
    <실행결과>
• ${number}: 10000
• ${{number}}: 10000
• ${ipPort}: hello.typeconverter.type.IpPort@59cb0946
• ${{ipPort}}: 127.0.0.1:8080

th:field는 자동으로 컨버전 서비스를 적용해줘서 ${{...}}처럼 적용됨

포맷터

Converter 는 입력과 출력 타입에 제한이 없는, 범용 타입 변환 기능 제공
Formatter는 객체를 특정한 포멧에 맞추어 문자로 출력하거나 또는 그 반대의 역할을 하는 것에 특화된 기능 제공 + 문자에 특화됨
우리가 웹 애플리케이션을 생각해보면, 문자를 다른 객체로 변환하거나 객체를 문자로 변환하는 일이 대부분임
ex) "1,000"을 1000으로 변환하는 일

포맷터는 객체를 문자로 변경하고, 문자를 객체로 변경하는 두 가지 기능을 모두 수행함
String print(T object, Locale locale) : 객체를 문자로 변경
T parse(String text, Locale locale) : 문자를 객체로 변경

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

컨버전 서비스에는 컨버터만 등록할 수 있고, 포맷터를 등록할 수 는 없지만, 생각해보면 포맷터는 객체 문자, 문자 객체로 변환하는 특별한 컨버터일 뿐
포맷터를 지원하는 컨버전 서비스를 사용하면 컨버전 서비스에 포맷터를 추가할 수 있다. 내부에서 어댑터 패턴을 사용해서 Formatter 가 Converter 처럼 동작하도록 지원함
FormattingConversionService 는 포맷터를 지원하는 컨버전 서비스

DefaultFormattingConversionService 는 FormattingConversionService 에 기본적인 통화, 숫자 관련 몇가지 기본 포맷터를 추가해서 제공, 사용할 때는 ConversionService 가 제공하는 convert 를 사용하면 됨

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

스프링은 자바에서 기본으로 제공하는 타입들에 대해 수 많은 포맷터를 기본으로 제공하지만, 포맷터는 기본 형식이 지정되어 있기 때문에, 객체의 각 필드마다 다른 형식으로 포맷을 지정하기는 어려움
스프링은 이런 문제를 해결하기 위해 애노테이션 기반으로 원하는 형식을 지정해서 사용할 수 있는 매우 유용한 포맷터 두 가지를 기본으로 제공함

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

컨버터를 사용하든, 포맷터를 사용하든 등록 방법은 다르지만, 사용할 때는 컨버전 서비스를 통해서 일관성 있게 사용 가능

메시지 컨버터( HttpMessageConverter )에는 컨버전 서비스가 적용 X
특히 객체를 JSON으로 변환할 때 메시지 컨버터를 사용하면서 이 부분을 많이 오해하는데, HttpMessageConverter 의 역할은 HTTP 메시지 바디의 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력하는 것, 따라서 JSON 결과로 만들어지는 숫자나 날짜 포맷을 변경하고 싶으면 해당 라이브러리가 제공하는 설정을 통해서 포맷을 지정해야 함, 결과적으로 이것은 컨버전 서비스와 전혀 관계가 없음

컨버전 서비스는 @RequestParam , @ModelAttribute , @PathVariable , 뷰 템플릿 등에서 사용할 수 있움!

profile
Novice Developer's Blog

0개의 댓글