PropertyEditor의 여러가지 장점에도 불구하고, PropertyEditor는 매번 바인딩을 할 때마다 새로운 오브젝트를 만들어야 한다는 약점이 있다.
그래서 스프링 3.0에는 PropertyEditor를 대신할 수 있는 새로운 타입 변환 API가 도입됐다. 바로 Converter 인터페이스다. Converter는 PropertyEditor와 다르게 변환과정에서 메소드가 한 번만 호출된다.
⇒ 변환 작업 중 상태를 인스턴스 변수로 저장하지 않음 (멀티스레드 환경에서 안전)
Converter
Converter는 소스 타입에서 타깃 타입으로의 단방향 변환만 지원한다. (PropertyEditor는 양방향 지원)
물론 소스 타입과 타깃 타입을 바꿔서 컨버터를 하나 더 만들면 양방향 변환이 가능해 진다.
converter 인터페이스
public interface Converter<S, T>{
T converter(S source);
}
앞에서 PropertyEditor로 구현한 것을 컨버터로 변경해보자. (양방향 변환을 위해 2개의 클래스를 구현한다.)
public class StringToLevelConverter implements Converter<String, Level> {
@Override
public Level convert(String s) {
return Level.valueOf(Integer.parseInt(s));
}
}
public class LevelToStringConverter implements Converter<Level, String> {
@Override
public String convert(Level level) {
return String.valueOf(level.intValue());
}
}
ConversionService
이렇게 만든 컨버터를 컨트롤러의 바인딩 작업에 사용하려면, ConversionService를 이용해야 한다.
ConversionService 타입의 오브젝트를 통해 WebDataBinder에 설정해줘야 한다. ConversionService는 여러 종류의 컨버터를 이용해서 하나 이상의 타입 변환 서비스를 제공해주는 오브젝트를 만들 때 사용하는 인터페이스이다.
보통 ConversionService를 구현한 GenericConversionService클래스를 빈으로 등록해서 사용한다.
GenericConversionService는 일반적으로 빈으로 등록하고 필요한 컨트롤러에서 DI받아서 @InitBinder 메소드를 통해 WebDataBinder에 설정하는 방식으로 사용한다.
@MVC 컨트롤러의 메소드 파라미터를 위해 사용하는 WebDataBinder에 GenericConversionService를 설정하는 방법은 두가지가 있다.
1. @InitBinder를 통한 수동 등록
ConversionServiceFactoryBean을 이용해서 프로퍼티로 DI 받은 컨버터들로 초기화된 GenericConversionService를 가져온다.
<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters"> <!-- GenericConversionService에 추가할 컨버터 지정 -->
<bean class="....LevelToStringConverter"/>
<bean class="....StringToLevelConverter"/>
</property>
</bean>
ConversionService타입의 빈을 DI 받아 WebDataBinder에 넣어준다.
@Controller
public class SearchController{
@Autowired
ConversionService conversionService;
@InitBinder
public void initBinder(WebDataBinder dataBinder){
dataBinder.setConversionService(conversionService);
}
}
2. ConfigurableWebBindingInitializer를 이용한 일괄 등록
모든 컨트롤러에 한 번에 적용하는 방법이다.
WebBindingInitializer는 모든 컨트롤러에 일괄 적용되는 @InitBinder 메소드를 정의한 것이라고 볼 수 있다.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer" ref="webBindingInitializer"/>
</bean>
<!-- 빈 설정만으로도 WebBindingInitilizer 빈을 등록할 수 있음 -->
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
</bean>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters"> <!-- GenericConversionService에 추가할 컨버터 지정 -->
<bean class="....LevelToStringConverter"/>
<bean class="....StringToLevelConverter"/>
</property>
</bean>
'프로그래밍 노트 > SPRING' 카테고리의 다른 글
[Spring] Environment 프로파일/프로퍼티 (0) | 2020.03.11 |
---|---|
[Spring] 모델 바인딩과 검증_3(Validator, BindingResult, Errors) (0) | 2020.01.06 |
[Spring] 모델 바인딩과 검증_1 (0) | 2019.12.23 |
[Spring] @ModelAttribute, @RequestAttribute (5) | 2019.07.17 |
[Spring] junit을 활용한 스프링 테스트 (0) | 2018.09.21 |