Spring은 기본적인 컨버터를 제공하지만, 컨버터를 커스텀하게 구현할 수도 있다. 예를 들면, String 값을 특정 객체를 변환하고 싶다면 커스텀 컨버터를 구현해야 한다.
강의 실습을 따라 String
값을 Person
객체로 변환하는 컨버터를 구현해보자. Person
객체는 name
과 age
필드를 갖는다.
Controller에서 URL 파라미터를 Person
객체로 반환해야 한다면 커스텀 컨버터를 구현 후, WebMvcConfigurer
에서 등록해야 한다.
@GetMapping("/type-converter")
public void typeConverter(@RequestParam Person person) {
log.info("person.getName() = {}", person.getName());
log.info("person.getAge() = {}", person.getAge());
}
다음과 같이 Converter
인터페이스를 implements
한 StringToPersonConverter
클래스를 만든다. 그리고 convert()
메서드를 오버라이드 한다. convert()
메서드 내부에서는 "gom:1200"
과 같은 문자열이 들어오면 :
를 기준으로 나눈 후 이름과 나이를 구해 새로운 Person
객체를 반환하고 있다.
public class StringToPersonConverter implements Converter<String, Person> {
// source = "gom:1200"
@Override
public Person convert(String source) {
String[] parts = source.split(":");
String name = parts[0];
int months = Integer.parseInt(parts[1]);
int age = months / 12;
return new Person(name, age);
}
}
그 다음 WebMvcConfigurer
인터페이스를 implements
한 WebConfig
클래스를 만든다. WebConfig
클래스에 다음과 같이 커스텀 컨버터를 등록해야 한다. 오버라이드 한 addFormatters()
메서드 내부에 registry.addConverter()
를 통해 등록하자.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToPersonConverter());
registry.addConverter(new PersonToStringConverter());
}
}
이제 실행 후 Postman에서 테스트해본다. 정상적으로 작동하는 것을 볼 수 있다.
인텔리제이에서도 다음과 같이 이름과 나이가 잘 변환되어 출력된다.
Fomatter
는 Converter
보다 더 세밀한 문자열 포맷팅을 할 수 있는 기능이다. Formatter
인터페이스를 implements
해서 날짜, 숫자 같은 특정 데이터 포맷으로 변환해보자.
다음과 같이 Formatter
인터페이스를 implements
한 PriceFormatter
클래스를 만든다. 그리고 parse()
메서드와 print()
메서드를 오버라이드한다.
@Slf4j
public class PriceFormatter implements Formatter<Number> {
@Override
public Number parse(String text, Locale locale) throws ParseException {
log.info("text = {}, locale={}", text, locale);
// 기본 제공되는 기능 숫자 중간에 (,) 쉼표를 넣어준다.
NumberFormat format = NumberFormat.getInstance(locale);
return format.parse(text);
}
@Override
public String print(Number object, Locale locale) {
log.info("object = {}, locale = {}", object, locale);
return NumberFormat.getInstance(locale).format(object);
}
}
컨버터와 같이 WebConfig
에 등록해준다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new PriceFormatter());
}
}
Postman에서 잘 실행되는 모습을 볼 수 있다.
인텔리제이에서도 잘....되나? 했는데 당연히 위에 적어놓은 Log가 찍힐 줄 알았는데 찍히지 않았다. 찾아보니 Spring이 내부적으로 StringToBigDecimalConverter
과 같은 기본 변환기를 사용해 변환할 수 있기 때문에 PriceFormatter
가 실행되지 않을 가능성이 있다고 한다.
그래서 addFormatterForFieldType()
을 사용해 특정 타입에 대해 강제로 PriceFormatter
를 사용하도록 설정하니 로그가 제대로 찍혔다. 하지만 기본 변환기로 변환이 되는거라면 굳이 강제로 사용하게 할 이유는 없는 것 같다..🤔 이 부분은 더 알아봐야겠다.
Relationship
테이블 하나로만 관리했는데, 몇몇 조는 FriendShip(Relationship)
테이블과 같이 Friend
테이블도 따로 만들었다. FriendShip(Relationship)
테이블만 활용하기 vs Friend
테이블도 같이 활용하기 → 각각 어떤 이점이 있고, 더 나은 방식(혹은 실무에서 더 많이 사용되는 방식)은 무엇일까?Friend
도 같이 활용한다면 친구 목록을 조회할 때 간편할 것 같고, 쿼리도 복잡하지 않을 것 같다. 하지만 FriendShip(Relationship)
만으로도 조회가 가능한데 또 테이블을 만드는 게 성능에 영향을 미치지 않을까? 하는 생각도 든다. ConversionService
로 등록하기 vs WebMvcConfiguere
로 등록하기 → 뭐가 더 나을까?오늘은 앉아있던 시간에 비해 한 게 없어서 아쉽다. 강의를 보고 이해하고, 정리하기까지 시간이 오래 걸리는 것 같다. 처음 배우는 내용이니 그럴 수 밖에 없지만 조급해지는 건 어쩔 수 없다. 또 스스로 완전히 몰입했다고 말할 수도 없기 때문에 더 집중하도록 노력하자.