본 게시물은 스스로의 공부를 위한 글입니다.
틀린 내용이 있을 수 있습니다.
String
)으로 처리되기 때문에 자바에서 다른 타입으로 변환하는 과정을 거쳐야 했다.@RequestParam
을 사용한다면? Integer
타입으로 받을 수 있다는걸 이미 알고 있을것이다. (@ModelAttribute
, @PathVariable
도 마찬가지)Q) HTTP 요청 파라미터는 모두
String
인데, 어떻게Integer
타입으로 받을 수 있는거지?
- A) 스프링이 중간에서 타입을 변환해주기 때문이다.
127.0.0.1:8080
인 String
을 사용자가 만든 클래스인 IpPort
로 변환하게 구현을 할것이다.public class IpPort {
private String ip;
private int port;
public IpPort(String ip, int port) {
this.ip = ip;
this.port = port;
}
}
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);
}
}
//등록
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToIpPortConverter());
//사용
IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
아! 그러면 등록하는 인터페이스와 사용하는 인터페이스를 분리하면, 사용할땐 컨버터 이름을 몰라도, 알아서 변환시켜 주는구나!
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToIpPortConverter());
}
}
@RequestParam
, @ModelAttribute
, @PathVariable
에서 알아서 컨버트해준다.//잘 동작하는지 확인. "127.0.0.1:8080"을 RequestParam으로 받아보자.
@GetMapping("/myIp")
public String ipPort(@RequestParam IpPort data) {
System.out.println("ipPort IP = " + ipPort.getIp());
System.out.println("ipPort PORT = " + ipPort.getPort());
return "ok";
}
범용 기능 컨버터는 이미 스프링에서 등록까지 다 되어있다.
개발자 입장에서는 객체를 특정한 포멧에 맞추어 문자로 출력하는 등의 기능이 필요할 수 있다.(예를 들어 숫자 1000
을 문자 1,000
으로 변환, 날짜 객체를 문자인 yy-MM
와 같이 출력하는 등)
이런 기능을 포맷터(Formatter
)라고 한다. 포맷터는 컨버터의 특벌한 버전이라고 이해하면 된다.
Converter vs Formatter
1000
을 문자 1,000
으로 만드는 포맷을 만들고 적용해보자.public class MyNumberFormatter implements Formatter<Number> {
@Override
public Number parse(String text, Locale locale) throws ParseException {
log.info("text={}, locale={}", text, locale);
//쉼표 넣는 기능은 NumberFormat에 구현되어있다.
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);
}
}
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addFormatter(new MyNumberFormatter());
Configuration
에 등록하기(단, 우선 순위는 컨버터가 더 우선이다.)@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new MyNumberFormatter());
}
}
http://localhost:8080/test?data=1,000
을 요청한다 해보자.@GetMapping("/test")
public String ipPort(@RequestParam Integer data) {
log.info("data={}", data);
return "ok";
}
Integer
인 1000
으로 받은것을 알 수 있다.@NumberFormat
: 숫자 관련 형식 지정 포맷터 사용@DateTimeFormat
: 날짜 관련 형식 지정 포맷터 사용@Data
static class Form {
@NumberFormat(pattern = "###,###")
private Integer number;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
@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";
}
@PostMapping("/formatter/edit")
public String formatterEdit(@ModelAttribute Form form) {
return "formatter-view";
}
formatter-form.html
<form th:object="${form}" th:method="post">
number
<input type="text" th:field="*{number}"><br/>
localDateTime
<input type="text" th:field="*{localDateTime}"><br/>
<input type="submit"/>
</form>
formatter-view.html
${{form.number}}: <span th:text="${{form.number}}" ></span>
${{form.localDateTime}}: <span th:text="${{form.localDateTime}}" ></
span>
${{form.number}}: 10,000
${{form.localDateTime}}: 2021-01-01 00:00:00
th:text="${{ ~ }}"
을 사용해야 한다.model.addAttribute
에 포맷팅된 값이 잘 들어간것을 확인 할 수 있다.PostMappting
에서 @ModelAttribute Form form
로 포맷팅된 값을 잘 받은것을 알 수 있다.❌주의❌
메시지 컨버터(HttpMessageConverter
)에는 컨버전 서비스가 적용되지 않는다.
예를 들어서 JSON을 객체로 변환하는 메시지 컨버터는 내부에서 Jackson
같은
라이브러리를 사용한다.
JSON 결과로 만들어지는 숫자나 날짜 포맷을 변경하고 싶으면 해당 라이브러리가 제공하는 설정을 통해서 포맷을 지정해야 한다.
결과적으로 이것은 컨버전 서비스와 전혀 관계가 없다.
컨버전 서비스는 @RequestParam
, @ModelAttribute
, @PathVariable
, 뷰 템플릿 등에서 사용할 수 있다.
인프런의 '스프링 MVC 2편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요