728x90
- 컨버전 서비스에는 컨버터만 등록할 수 있고, 포맷터를 등록할 수는 없다. 그런데 생각해보면 포맷터는 객체 -> 문자, 문자 -> 객체로 변환하는 특별한 컨버터일 뿐이다.
- 포맷터를 지원하는 컨버전 서비스를 사용하면 컨버전 서비스에 포맷터를 추가할 수 있다. 내부에서 어댑터 패턴을 사용해서 Formatter 가 Converter처럼 동작하도록 지원한다
- FormattingConversionService는 포맷터를 지원하는 컨버전 서비스이다.
- DefaultFormattingConversionService 는 FormattingConversionService에 기본적인 통화, 숫자 관련 몇 가지 기본 포맷터를 추가해서 제공한다.
public class FormattingConversionServiceTest {
@Test
public void formattingConversionService(){
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
//컨버터 등록
conversionService.addConverter(new StringToIpPortConverter());
conversionService.addConverter(new IpPortToStringConverter());
//포맷터 등록
conversionService.addFormatter(new MyNumberFormatter()); //컨버터기능도 되고 , 포맷터 기능도 된다
//컨버터 사용
IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
assertThat(ipPort).isEqualTo(new IpPort("127.0.0.1", 8080));
//포멧터 사용
assertThat(conversionService.convert(1000, String.class)).isEqualTo("1,000");
assertThat(conversionService.convert("1,000", Long.class)).isEqualTo(1000L);
}
}
- FormattingConversionService는 ConversionService 관련 기능을 상속받기 때문에 결과적으로 컨버터도 포맷터도 모두 등록할 수 있다. 그리고 사용할 때는 ConversionService 가 제공하는 convert를 사용하면 된다
- 추가로 스프링 부트는 DefaultFormattingConversionService 를 상속받은 WebConversionService를 내부에서 사용한다
포맷터 적용하기
@Override
public void addFormatters(FormatterRegistry registry) {
// 우선순위 떄문에 주석 처리
// 컨버터가 우선 순위가 높다
//registry.addConverter(new StringToIntegerConverter());
//registry.addConverter(new IntegerToStringConverter());
registry.addConverter(new StringToIpPortConverter());
registry.addConverter(new IpPortToStringConverter());
//추가
registry.addFormatter(new MyNumberFormatter());
}
- 주의 StringToIntegerConverter , IntegerToStringConverter 를 꼭 주석처리 하자. MyNumberFormatter 도 숫자 문자, 문자 숫자로 변경하기 때문에 둘의 기능이 겹친다.
- 우선순위는 컨버터가 우선하므로 포맷터가 적용되지 않고, 컨버터가 적용된다
스프링이 제공하는 기본 포맷터
- 스프링은 자바에서 기본으로 제공하는 타입들에 대해 수 많은 포맷터를 기본으로 제공한다.
- IDE에서 Formatter 인터페이스의 구현 클래스를 찾아보면 수많은 날짜나 시간 관련 포맷터가 제공되는 것을 확인할 수 있다.
- 그런데 포맷터는 기본 형식이 지정되어 있기 때문에, 객체의 각 필드마다 다른 형식으로 포맷을 지정하기는 어렵다
- 스프링은 이런 문제를 해결하기 위해 애노테이션 기반으로 원하는 형식을 지정해서 사용할 수 있는 매우 유용한 포맷터 두 가지를 기본으로 제공한다.
- @NumberFormat : 숫자 관련 형식 지정 포맷터 사용, NumberFormatAnnotationFormatterFactory
- @DateTimeFormat : 날짜 관련 형식 지정 포맷터 사용, Jsr310DateTimeFormatAnnotationFormatterFactory
@Controller
public class FormatterController {
@GetMapping("/formatter/edit")
public String formatterForm(Model model){
Form form = new Form();
form.setNumber(10000);
form.setLocalDateTime(LocalDateTime.now());
model.addAttribute("form", form);
return "formatter-form";
}
//"10,000" -> 10000
@PostMapping("/formatter/edit")
public String formatterEdit(@ModelAttribute Form form){
return "formatter-view";
}
@Data
static class Form{
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
}
- @NumberFormat , @DateTimeFormat의 자세한 사용법이 궁금한 분들은 다음 링크를 참고하거나 관련 애노테이션을 검색해보자.
Core Technologies
In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do
docs.spring.io
주의
- 메시지 컨버터( HttpMessageConverter )에는 컨버전 서비스가 적용되지 않는다. 특히 객체를 JSON으로 변환할 때 메시지 컨버터를 사용하면서 이 부분을 많이 오해하는데, HttpMessageConverter의 역할은 HTTP 메시지 바디의 내용을 객체로 변환하거나 객체를 HTTP 메시지 바디에 입력하는 것이다.
- 예를 들어서 JSON을 객체로 변환하는 메시지 컨버터는 내부에서 Jackson 같은 라이브러리를 사용한다. 객체를 JSON으로 변환한다면 그 결과는 이 라이브러리에 달린 것이다.
- 따라서 JSON 결과로 만들어지는 숫자나 날짜 포맷을 변경하고 싶으면 해당 라이브러리가 제공하는 설정을 통해서 포맷을 지정해야 한다.
- 결과적으로 이것은 컨버전 서비스와 전혀 관계가 없다. 컨버전 서비스는 @RequestParam , @ModelAttribute , @PathVariable , 뷰 템플릿 등에서 사용할 수 있다
728x90
'스프링 MVC 2편(백엔드 웹 개발 활용 기술)' 카테고리의 다른 글
| Ch11. 파일 업로드 - 서블릿과 파일 업로드 (0) | 2022.03.23 |
|---|---|
| Ch11. 파일 업로드 - 파일 업로드 소개 (0) | 2022.03.23 |
| Ch10. 스프링 타입 컨버터 소개 - 포맷터(Formatter) (0) | 2022.03.22 |
| Ch10. 스프링 타입 컨버터 소개 - 뷰 템플릿에 컨버터 적용하기 (0) | 2022.03.22 |
| Ch10. 스프링 타입 컨버터 소개 - 스프링에 Converter 적용하기 (0) | 2022.03.22 |