Converter
- S 타입을 T 타입으로 변환할 수 있는 매우 일반적인 변환기
- 상태 정보 없음 == Stateless = 쓰레드세이프
public class EventConverter {
public static class StringToEventConverter implements Converter<String, Event>{
@Override
public Event convert(String source) {
return new Event(Integer.parseInt(source));
}//String에서 Event로 Event/Constructor에 source를 넘긴다.
}
public static class EventToString implements Converter<Event, String>{
@Override
public String convert(Event source) {
return source.getId().toString();
//쉽게 event에서 Id를 받아와서 toString하면 끝
}
}
}
ConverterRegistry 에 등록해서 사용
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new EventConverter.StringToEventConverter());
//converter 등록!
//이렇게 등록을 해주면, WevMvcConfigurer 웹 Mvc 설정에서 우리가 넣어준 converter가 Controller에서 요청한 "1"이
//converter에서 event로 변환이 되서, 우리가 event 타입으로 받을 수 있는것이다.
}
}
https://hsoh1990.github.io/2019/01/25/spring-core-binding/
Formatter
- 쓰레드-세이프 하기때문에 빈으로 등록 할수있다.
- PropertyEditor 대체제
- Object와 String 간의 변환을 담당한다.
- 문자열을 Locale에 따라 다국화하는 기능도 제공한다. (optional) - web쪽에 특화 되어있다.
public class EventFormatter implements Formatter<Event> {
@Override
public Event parse(String text, Locale locale) throws ParseException {
return new Event(Integer.parseInt(text));
}
@Override
public String print(Event event, Locale locale) {
return event.getId().toString();
}
}
FormatterRegisrty 에 등록해서 사용
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
//addFormatter(new EventFormatter());
registry.addFormatter(new EventFormatter());
}
}
ConversionService
- 실제 변환 작업은 이 인터페이스를 통해서 쓰레드-세이프하게 사용할 수 있음.
- 스프링 MVC, 빈(value) 설정, SpEL에서 사용한다.
- DefaultFormattingConversionService
- FormatterRegistry
- ConversionService
- 여러 기본 컴버터와 포매터 등록해줌.
스프링 부트
- 웹 애플리케이션인 경우에 DefaultFormattingConversionSerivce를 상속하여 만든 WebConversionService를 빈으로 등록해 준다.
- Formatter와 Converter 빈을 찾아 자동으로 등록해 준다.
ConversionService을 빈으로 자동으로 주입을 받을수 있는지 테스트 해보자.
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ConversionService conversionService;
//우리가 직접 conversionService를 주입받는일은 거의 없을 것이다.
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(conversionService.getClass().toString());
}
}
출력 결과
class org.springframework.boot.autoconfigure.web.format.WebConversionService
DefaultFormattingConversionService가 나오는게 아니고, WebConversionService가 나온다.
왜냐하면, WebConversionService은 스프링부트가 제공해주는 클래스이기 때문이다.
WebConversionService는 DefaultFormattingConversionService를 상속받고 있다.
public class WebConversionService extends DefaultFormattingConversionService {
private static final boolean JSR_354_PRESENT = ClassUtils.isPresent("javax.money.MonetaryAmount", WebConversionService.class.getClassLoader());
...
}
근데 우리가 ConverisionService 를 직접 사용하는 경우는 드물고,
스프링 부트 에서 Formatter와 Converter 빈을 찾아서 자동으로 등록을 해준다.
(Converter, Formatter가 빈으로 등록이 되어있다면, 그 빈들을 ConversionService가 자동으로 빈으로 등록을 해준다.)
그러면 WebConfig 클래스는 필요가 없어진다. ( ConversionService를 사용하게 되면 아무런 web설정 클래스를 만들지 않아도된다. )
public class EventConverter {
@Component //빈으로 등록해주면? 자동으로 coverter, formatter를 등록해준다.
public static class StringToEventConverter implements Converter<String, Event>{
@Override
public Event convert(String source) {
return new Event(Integer.parseInt(source));
}
}
@Component //빈으로 등록해주면? 자동으로 coverter, formatter를 등록해준다.
public static class EventToString implements Converter<Event, String>{
@Override
public String convert(Event source) {
return source.getId().toString();
}
}
}
이런식으로 Converter를 구현하는 클래스들을 빈으로 등록을 해주면 된다.
Formatter도 @Component 를 붙여주면 자동으로 등록이 된다.
@Component
public class EventFormatter implements Formatter<Event> {
@Override
public Event parse(String text, Locale locale) throws ParseException {
return new Event(Integer.parseInt(text));
}
@Override
public String print(Event event, Locale locale) {
return event.getId().toString();
}
}
스프링 부트 계층형 테스트 : @WebMvcTest
@RunWith(SpringRunner.class)
@WebMvcTest({EventFormatter.class ,EventController.class})
// 빈으로 등록. 내가 테스트를 할때 필요한 빈들이 눈에 보이기때문에 빈으로 등록함으로써 명시해주는것도 나쁘지 않다.
// 빈으로 등록하기전엔, component-scan이 가능한 클래스여야한다. (@Component , @Controller 등)
public class EventControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void getText() throws Exception {
mockMvc.perform(get("/event/1"))
.andExpect(status().isOk())
.andExpect(content().string("1"));
}
}
@WebMvcTest({EventFormatter.class ,EventController.class})
//EventFormatter 클래스와 EventController 클래스를 테스트 하겠다.
그냥 클래스만 준다고 다 되는건 아니고, 컴포넌트 스캔이 가능한 클래스여야지만 가능하다. (@Component , @RestController 등)
//등록되어있는 컨버터를 모두 보는법
@Autowired
ConversionService conversionService;
System.out.println(conversionService); //그냥 출력 하면 됨
Converter보다 Formatter를 더 추천한다고 한다. (Converter는 자동으로 등록이 되어있는 경우가 있다)