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๋ ์๋์ผ๋ก ๋ฑ๋ก์ด ๋์ด์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค)