스프링 타입 컨버터
문자를 숫자로 변환하거나, 숫자를 문자로 변환하는 과정을 스프링 MVC 에서는 편리하게 지원해준다.
ex) 데이터 타입 변환: 문자열을 정수로 변환
일반적인 컨버터 방법
HTTP 요청 파라미터는 무조건 문자로 처리된다. 그러므로 숫자를 사용하고 싶으면 숫자 타입 변환을 해줘야한다.
@RestController
public class HelloController {
@GetMapping("/hello-v1")
public String helloV1(HttpServletRequest request) {
String data = request.getParameter("data"); //문자 타입 조회
Integer intValue = Integer.valueOf(data); //숫자 타입으로 변경
System.out.println("intValue = " + intValue);
return "ok";
}
}
스프링 MVC 를 이용한 컨버터 방법
MVC에서는 스프링 MVC 요청 파라미터(@RequestParam, @ModelAttribute, @PathVariable )이나 뷰를 렌더링할 때 등 스프링에서 자동으로 입력한 타입에 맞게 변환을 해준다.
@GetMapping("/hello-v2")
public String helloV2(@RequestParam Integer data) {
System.out.println("data = " + data);
return "ok";
}
하지만 이런 간단한 타입 변환말고 새로운 타입을 만들어서 변환하고 싶을 때는 어떻게 해야 할까?
컨버터 인터페이스
스프링은 확장 가능한 컨버터 인터페이스를 제공한다. 추가 타입 변환이 필요하면 해당 인터페이스를 구현해서 등록하면 된다.
public interface Converter<S, T> {
T convert(S source);
}
사용자 정의 타입 컨버터 예시
1. IpPort 정의
@Getter
@EqualsAndHashCode
public class IpPort {
private String ip;
private int port;
public IpPort(String ip, int port) {
this.ip = ip;
this.port = port;
}
}
2. 컨버터 정의 (String To IpPort)
Ip와 port가 합쳐진 문자를 입력하면 IpPort 객체로 변환하는 컨버터
ex) Ip+Port : 128.0.0.1:8080 -> IpPort : IpPort(ip=128.0.0.1, Port=8080)
@Slf4j
public class StringToIpPortConverter implements Converter<String, IpPort> {
@Override
public IpPort convert(String source) {
log.info("convert source={}", source);
String[] split = source.split(":");
String ip = split[0];
int port = Integer.parseInt(split[1]);
return new IpPort(ip, port);
}
}
3. 컨버터 정의 (IpPort To String)
IpPort 객체를 입력하면 String으로 변환하는 컨버터
ex) IpPort : IpPort(ip=128.0.0.1, Port=8080) -> Ip+Port : 128.0.0.1:8080
@Slf4j
public class IpPortToStringConverter implements Converter<IpPort, String> {
@Override
public String convert(IpPort source) {
log.info("convert source={}", source);
return source.getIp() + ":" + source.getPort();
}
}
컨버전 서비스 - ConversionService
위처럼 타입 컨버터를 하나하나 직접 찾아서 타입 변환에 사용하는 것은 매우 불편하다. 그래서 스프링에서 컨버터들을 모아두고 묶어서 편리하게 사용할 수 있는 컨버전 서비스를 제공해준다.
ConversionService 인터페이스
public interface ConversionService {
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(@Nullable Object source, Class<T> targetType);
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,TypeDescriptor targetType);
}
ConversionService 등록 - WebConfig 컨버터 등록
스프링 내부에서는 ConversionService를 제공해준다.
WebMvcConfigurer가 제공하는 addFormatter를 통해 추가하고 싶은 컨버터를 등록하면 된다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new IpPortToStringConverter());
registry.addConverter(new StringToIpPortConverter());
}
}
뷰 템플릿에 컨버터 적용
타임리프는 렌더링 시 컨버터를 적용해서 렌더링하는 방법을 지원해준다. 타임리프는 ${{..}}를 사용하면 자동으로 컨버전 서비스를 사용하여 변환된 결과를 출력해준다.
<ul>
<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>
</ul>
* th:fied 는 컨버전 서비스가 자동으로 적용된다.
* 메세지 컨버터에는 컨버전 서비스가 적용되지 않는다.
포맷터 - Formatter
Converter은 입력과 출력 타입에 제한이 없는, 범용 타입 변환 기능을 제공한다. 컨버터와 달리 Formatter은 말그대로 포맷팅을 해준다.
ex) 날짜 서식 설정: 2024-05-31 ->31/05/2024 문자열 포맷: 숫자 1234.5678 ->1,234.57로 포맷
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> {}
- print : 객체를 문자로 변경
- parse : 문자를 객체로 변경
- local : 현지화 정보 입력
포맷팅 정의
parse : String 1,000 to Integer 1000
print : Integer 1000 to String 1,000
@Slf4j
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 객체를 사용
포맷팅 등록
컨버전 서비스는 컨버터만 등록할 수있다. 하지만 포맷터는 어떻게 보면 특별한 컨버터일 뿐이다. 그래서 포맷터를 지원하는 컨버전 서비스를 사용하면 포맷터를 추가할 수 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToIpPortConverter());
registry.addConverter(new IpPortToStringConverter());
//추가
registry.addFormatter(new MyNumberFormatter());
}
}
* 우선순위는 컨버터가 우선임을 유의해야한다.
포맷팅 결과
${number}: 10000
${{number}}: 10,000
스프링이 제공하는 기본 포맷터
스프링에서는 날짜나 숫자의 포맷팅을 편리하게 해주는 애노테이션 기반의 포맷터를 지원해준다.
- @NumberFormat : 숫자 관련 형식 지정 포맷터 사용
- @DateTimeFormat : 날짜 관련 형식 지정 포맷터 사용
Form 정의
@Data
static class Form {
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
}
FormController 정의
@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";
}
포맷팅 결과
${form.number}: 10000
${{form.number}}: 10,000
${form.localDateTime}: 2021-01-01T00:00:00
${{form.localDateTime}}: 2021-01-01 00:00:00
'웹 개발' 카테고리의 다른 글
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 파일 업로드 (0) | 2024.06.01 |
---|---|
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 예외 처리 (0) | 2024.05.30 |
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 로그인 처리 (0) | 2024.05.30 |
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 검증 (0) | 2024.05.30 |
intellij 단축키 (0) | 2024.04.16 |