Spring/MVC

스프링 MVC 2편 -10장. 스프링 타입 컨버터

광터틀 2022. 9. 5. 15:00

스프링 MVC 2편 -10장. 스프링 타입 컨버터 (인프런 - 김영한 강사님) 

 

타입 컨버터에 대해 배우는 단원이다. 

문자를 받아서 숫자 타입으로 변경해야할 일이 있다고 하자. 

매번 HttpServletRequest request를 불러서 파라미터를 받아 data에 저장하고, 문자 타입인 data를 Integer.valueOf(data)를 통해서 숫자 타입으로 변경해주기는 힘들다. 


-> @RequestParam 사용하기 

스프링 MVC는 @RequestParam을 통해 타입을 중간에 변경해주므로 쉽게 타입을 변경할 수 있다. 

(@ModelAttribute, @PathVariable도 타입을 중간에 변경해준다.)

다음 코드에서 HTTP 쿼리 스트링으로 전달받는 data=10 부분에서 10은 문자 10이었으나 

@RequestParam Integer data로 써줌으로 인해 문자 10이 숫자 10으로 받아진다. 

 

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

 

 

개발자가 String, Integer 등이 아닌 새로운 타입을 만들어서 변환하고 싶다면 스프링에서 제공하는 확장 가능한 컨버터 인터페이스를 사용하면 된다. 컨버터 인터페이스에 타입을 구현해서 등록하면 된다. 

 

1
2
3
4
5
package org.springframework.core.convert.converter;
 
public interface Converter<S, T> {
 T convert(S source);
}
cs

타입 컨버터 - Converter 

 

타입 컨버터를 직접 작성해보자.

String과 IpPort 타입을 서로 변환하는 컨버터 클래스를 작성한다. 

class StringToIpPortConverter 

class IpPortToStringConverter 

 

각각 String -> IpPort, IpPort -> String로 타입을 변환해주는 클래스들이다. 단순하긴 하나 이렇게 타입 컨버터를 하나하나 직접 사용해야 하면 위에서 개발자가 직접 컨버팅 했던 것과 큰 차이가 없다. 

 

타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 제공하는 역할로 컨버전 서비스가 있다. 


컨버전 서비스 - ConversionService 

 

위에 작성했던 네 개의 컨버터(문자열, 정수끼리의 변환, 문자열, IpPort끼리의 변환)을 등록하고 사용할 수 있게 해주는 인터페이스다. 

스프링 내부에서 ConversionService를 제공하므로 WebMvcConfigurer가 제공하는 addFormatters()를 사용해서 컨버터를 등록하면 된다. 그러면 알아서 스프링이 ConvserionService에 컨버터를 추가해준다. 

(사실 String, Integer 등 기본적인 타입들에 대한 컨버터들은 스프링이 기본적으로 제공한다. 따라서 StringToIntegerConverter 등은 직접 등록하지 않아도 된다. 

직접 만든 타입들을 등록하거나 새로운 컨버터를 추가하면 기본 컨버터보다 높은 우선순위를 갖는다.) 

 

 


포맷터 - Formatter 

 

포맷터는 컨버터의 특별한 버전이다. 

Converter는 범용 (객체 -> 객체) 이라면 

Formatter는 문자ㅔ 특화 (객체 -> 문자, 문자 -> 객체) + 현지화 

 

개발자 입장에서는 타입 변환 중에서도 문자를 다른 타입으로 변환하거나 다른 타입을 문자로 변환하는 상황이 대부분이기에 이럴 때 포맷터를 사용하면 된다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
//객체를 문자로 변경한다.
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> {
}
cs

 

 

위에서 봤던 컨버전 서비스에는 컨버터만 등록할 수 있고 포맷터는 등록할 수 없다. 포맷터는 조금 특별한 컨버터일 뿐이므로 포맷터도 컨버전 서비스에 등록할 수 있으면 더욱 좋다. 

 

FormattingConversionService는 포맷터를 지원하는 컨버전 서비스로 내부에서 어댑터 패턴을 사용해서 Formatter가 Converter처럼 동작하도록 지원한다. 컨버터와 포맷터를 모두 등록, 사용할 수 있고 convert를 사용하면 된다. 다만 컨버터와 포맷터가 동시에 있으면 컨버터에 우선순위가 간다. 

 

 

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

@NumberFormat

@DataTimeFormat