일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 스프링 빈
- HTTP 요청 메시지
- 백준 2263
- 백준4256
- 프로토타입 스코프
- 언체크에러
- 객체지향
- 커밋로그
- http
- 서블릿
- REST #REST API #HTTP 메서드
- BeanDefnition
- BasicErrorController
- 깃허브 저장소 합치기
- 스프링 타입컨버터
- 스프링
- 스프링 예외변환기
- 프로토콜 스택 4계층
- BeanValidation
- 예외추상화
- HTTP메시지
- 스프링 파일 업로드
- HTTP 응답 메시지
- 의존관계
- 김영한
- DI
- 체크에러
- 웹 스코프
- 스프링 컨테이너
- ExceptionResolver
- Today
- Total
Enthusiasm! Enthusiasm!
스프링 타입 컨버터 본문
애플리케이션을 개발하다 보면 문자를 숫자로 변환 하거나 숫자를 문자로 변환하는 것 처럼 타입을 변환해야 하는 경우가 많다. 빈번이 일어나는 타입변환은 스프링에서 기본으로 제공하지만, 개발자가 만든 타입을 다른 타입으로 변환해야 하는 경우도 있다. 이럴때 마다 개발자가 직접 하나하나 타입 변환을 해야 한다면, 개발의 효율이 상당히 떨어질 것이다. 이와 같은 문제를 스프링에서 어떻게 편리하게 해결 할 수 있는지 알아보자.
타입 컨버터 - Converter
public interface Converter<S, T> {
T convert(S source);
}
스프링은 위와 같이 확장 가능한 Converter 인터페이스를 제공한다. 이 인터페이스는 모든 타입에 적용할 수 있고, S타입을 T타입으로 변환한다. 양방향으로 변환을 하려면 <S,T> , <T,S> 인터페이스를 각각 구현해서 등록하면 된다.
주의: Converter라는 인터페이스가 많은데 org.springframework.core.convert.converter.Converter를 사용해야한다.
사용 예시
예시상황: 127.0.0.1:8080 과 같은 IP, PORT를 입력하면 IpPort 객체로 변환하는 컨버터를 설계
- IpPort 클래스
@Getter
@EqualsAndHashCode
public class IpPort {
private String ip;
private int port;
public IpPort(String ip, int port) {
this.ip = ip;
this.port = port;
}
※롬복의 @EqualsAndHashCode는 모든 필드를 사용해서 equals(), hashcode()를 생성한다. 즉 모든 필드의 값이 같아면 a.equals(b)의 결과가 참이 된다.
- StringToIpPortConverter
public class StringToIpPortConverter implements Converter<String, IpPort> {
@Override
public IpPort convert(String source) {
String[] split = source.split(":");
String ip = split[0];
int port = Integer.parseInt(split[1]);
return new IpPort(ip, port);
}
}
String 타입을 IpPort 타입으로 변환해주는 Converter로 127.0.0.1:8080과 같은 문자열을 IpPort객체로 변환하여 반환한다.
- IpPortToStringConverter
public class IpPortToStringConverter implements Converter<IpPort, String> {
@Override
public String convert(IpPort source) {
return source.getIp() + ":" + source.getPort();
}
}
IpPort 객체를 입력하면 127.0.0.1:8080 같은 문자를 반환한다
ConversionService
위와 같이 컨버터를 만들어 사용하려면 매번 컨버터 객체를 호출하여 사용해야하는 불편함이 있다. ConversionService는 타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 사용할 수 있게 해준다. 인터페이스를 보면 타입 컨버팅이 가능한지 확인하는 기능과 가능하다면 컨버팅을 해주는 기능이 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToIpPortConverter());
registry.addConverter(new IpPortToStringConverter());
}
}
다음과 같이 스프링에 등록하면 아래 코드와 같은 상황에서, 컨버터를 자동으로 호출하여 파라미터로 들어온 문자를 ipPort타입으로 변환해준다.
@GetMapping("/ip-port")
public String ipPort(@RequestParam IpPort ipPort) {
System.out.println("ipPort IP = " + ipPort.getIp());
System.out.println("ipPort PORT = " + ipPort.getPort());
return "ok";
}
URL: http://localhost:8080/ip-port?ipPort=127.0.0.0:8080
출력: ipPort IP = 127.0.0.0, ipPort PORT = 8080
뷰 템플릿과 폼에 컨버터 적용
뷰 템플릿에 컨버터를 적용할 때, 타임리프는 랜더링 시에 컨버터를 적용해서 렌더링 하는 방법을 편리하게 지원한다. 또한 모델에 데이터를 넣어 전송하기 때문에 객체를 문자로 변환하는 작업도 할 수 있다.
<li>${number}: <span th:text="${number}" ></span></li>
<li>${{number}}: <span th:text="${{number}}" ></span></li>
<li>${ipPort}: <span th:text="${ipPort}" ></span></li>
<li>${{ipPort}}: <span th:text="${{ipPort}}" ></span></li>
타임리프에서 ${{...}}을 사용하면 자동으로 컨버전 서비스를 사용해서 반환된 결과를 출력해준다. 스프링과 통합 되어서 스프링이 제공하는 컨버전 서비스를 사용하는 것으로, 우리가 등록한 컨버터들을 사용할 수 있다.
- ${...} -> 변수표현식
- ${{...}} -> 컨버전 서비스 적용
폼에서는 다음과 같이 컨버터를 적용한다.
<form th:object="${form}" th:method="post">
th:field <input type="text" th:field="*{ipPort}"><br/>
th:value <input type="text" th:value="*{ipPort}">(보여주기 용도)<br/> <input type="submit"/>
</form>
- @GetMapping("/converter/edit"): 폼에 출력되는 데이터는 th:field 가 자동으로 컨버전 서비스를 적용해주어서 ${{ipPort}} 처럼 적용이 된다.
- @PostMapping("/converter/edit"): 뷰 템플릿과 마찬가지로 모델을 통해 데이터를 전송하고 ${{...}}를 통해 변환된다.
포맷터 - Formatter
Converter는 입력과 출력 타입에 제한이 없는, 범용 타입 변환 기능을 제공한다. 하지만 다음과 같은 상황에서는 사용하기 어렵다.
- 화면에 숫자를 출력해야 하는데, Integer->String 출력 시점에 숫자 1000->문자 "1,000" 처럼 1000 단위에 쉼표를 넣어서 출력하거나, 또는 "1,000" 라는 문자를 1000 이라는 숫자로 변경해야 한다.
- 날짜 객체를 문자인 "2021-01-01 10:50:11" 와 같이 출력하거나 또는 그 반대의 상황
이렇게 객체를 특정한 포멧에 맞추어 문자로 출력하거나 또는 그 반대의 역할을 하는 것에 특화된 기능이 바로 Formatter이다. 포맷터는 컨버터의 특별한 버전으로 이해하면 된다.
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
- String print(T object, Locale locale) : 객체를 문자로 변경한다.
- T parse(String text, Locale locale) : 문자를 객체로 변경한다.
다음과 같이 구현하면 된다.
public class MyNumberFormatter 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);
}
}
스프링이 제공하는 기본 포맷터
스프링은 자바에서 기본으로 제공하는 타입들에 대해 수 많은 포맷터를 기본으로 제공한다. 그런데 포맷터는 기본 형식이 지정되어 있기 때문에, 객체의 각 필드마다 다른 형식으로 포맷을 지정하기는 어렵다. 스프링은 이런 문제를 해결하기 위해 애노테이션 기반으로 원하는 형식을 지정해서 사용할 수 있는 매우 유용한 포맷터 두 가지를 기본으로 제공한다.
- @NumberFormat: 숫자 관련 형식 지정 포맷터 사용
- @DateTimeFormat: 날짜 관련 형식 지정 포맷터 사용
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
위와 같이 패턴을 지정하여 사용하면 된다!
이 포스팅은 Inflearn 김영한님의 스프링 강의 및 강의자료를 참고하여 작성하였습니다.
'자바 스프링 > 스프링MVC' 카테고리의 다른 글
웹 애플리케이션의 이해 (0) | 2023.04.02 |
---|---|
스프링 파일 업로드 (0) | 2023.03.16 |
스프링 예외처리 (0) | 2023.03.15 |
스프링 인터셉터 (0) | 2023.03.08 |
검증 - BeanValidation (0) | 2023.03.03 |