티스토리 뷰
얼마전 포스팅했던 Joda Time에 대해 사내발표를 진행했는데... 사내 프로젝트 내에서 Date타입으로 선언된 필드들을 Joda Time으로 변경하자는 의견이 나왔고, 다른 개발자들이 별다른 설정이나 추가코드를 작성할 필요없이 Joda Time 클래스를 사용할 수 있게 하라는 지시가 내려왔다. 이렇게까지 일을 벌일(?) 생각은 없었는데 그 작업을 맡게되었고 일단 날짜 데이터를 화면에서 보내면 LocalDate(혹은 LocalDateTime)로 자동으로 받을 수 있게끔 작업하는것부터 시작이 됐어야했다. 그 작업을 포스팅으로 남겨두려한다.
1. Spring Data Binding
일단 Spring 컨트롤러는 매개변수로 변수를 넣어놓으면 알아서 해당 타입으로 값을 갖다 쓸 수있게 되어있다.
@RequestMapping("/hello")
public String hello(int page){
return "hello";
}
인자들이 여러개가 될경우 Command 객체를 인자로 받게하면 해당 객체로 받아주기도 한다.
@RequestMapping("/hello")
public String hello(Command command){
return "hello";
}
public static class Command{
private int page;
public void setPage(int page){
this.page = page;
}
public int getPage(){
return this.page;
}
}
별 생각없이 잘 쓰고있긴한데 이제와서 생각해보면 참 신통방통한 일이 아닐 수 없다. 스프링 없이 서블릿 기반으로 게시판만 하나 만들어봤으면 알 수 있겠지만 화면에서 전달되는 데이터는 기본적으로 String 타입이기 때문이다.
HttpServletRequest 의 getParameter() 메서드는 리턴타입이 String 인 이유이다. 결국은 어디선가 형변환을 해주는곳이 있다는 얘기가 된다.
2. Converter
날짜 형태로 넘어오는 값 역시 형태가 어찌됐든 문자열로 넘어올것이고, 그 문자열을 LocalDate 타입으로 변환해주는 코드를 작성해야한다는 의미가 된다. 그 역할을 해주는게 Converter이다.
Spring core 프로젝트에 있는 Converter<S, T> 인터페이스를 구현해주면 된다. S는 input 타입이고 T는 return 타입이다.
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S var1);
}
구현은 어려운게 없다. 그저 타입변환만 해주면 되니..
/**
* Created by LichKing on 2017. 3. 12..
*/
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
@Override
public LocalDate convert(String s) {
return LocalDate.parse(s, DATE_TIME_FORMATTER);
}
}
parse() 메서드는 인자를 1개만 받는 메서드도있는데 그 경우엔 기본 패턴이 yyyy-MM-dd 이다. 기본 형태로 넘겨준다면 따로 DateTimeFormatter 객체를 만들필요는 없다.
인자에대한 empty 체크 정도는 해줘야 할것 같다.
@Override
public LocalDate convert(String s) {
if(s == null || s.isEmpty()){
return null;
}
return LocalDate.parse(s, DATE_TIME_FORMATTER);
}
값이 없을때 기본날짜를 넘겨주거나 Optional을 넘겨주거나 null을 넘겨줄지는 정책을 정해서 가면 될 것 같다.
Converter는 만들었으니 이제 이걸 등록해주자. ConverterFactory 빈을 만들어줘야한다. 현재 XML 기반의 설정파일을 사용하고있으므로 XML 설정법으로 이어가겠다.
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.yong.spring.binding.StringToLocalDateConverter"/>
</set>
</property>
</bean>
빈을 생성하고
<mvc:annotation-driven conversion-service="conversionService">
서비스를 등록해주면 Converter를 통해 LocalDate로 넘어오는걸 확인할 수 있다.
@RequestMapping("/hello")
public String hello(Command command){
return "hello";
}
public static class Command{
private LocalDate date;
public void setDate(LocalDate date){
this.date = date;
}
public LocalDate getDate(){
return this.date;
}
}
#2017.04.09 추가
xml이 아닌 java 기반의 설정을 하고있다면 config 파일에 이렇게 추가해주면 된다.
@Override
public void addFormatters(FormatterRegistry registry){
registry.addConverter(new Converter<String, LocalDate>(){
@Override
public LocalDate convert(String s) {
return null;
}
});
}
나는 현재 xml기반으로 사용하고있고, 자바 설정 예제를 위해 간략히 짠거라 일단 익명 클래스 방식으로 했는데..java8을 사용한다면 xml로 설정할때처럼 따로 파일 만들필요없이 람다로 만들어놓으면 관리하기도 편할것 같기도하다(변환 코드가 짧다는 가정하에..).
@Override
public void addFormatters(FormatterRegistry registry){
registry.addConverter((String s) -> LocalDate.parse(s));
}
더 줄여서 메서드 레퍼런스로 만들어버리자
@Override
public void addFormatters(FormatterRegistry registry){
registry.addConverter((Converter<String, Object>) LocalDate::parse);
}
'Java > spring' 카테고리의 다른 글
Spring Bean 초기화/소멸 (0) | 2017.11.17 |
---|---|
static factory method를 이용한 spring bean 생성 (4) | 2017.11.16 |
List, Map Spring Bean 생성 (0) | 2017.02.24 |
intellij spring mvc 설정 (0) | 2016.07.20 |
Spring DI (0) | 2016.02.23 |
- Total
- Today
- Yesterday
- Design Pattern
- Git
- mariadb
- frontend개발환경
- generics
- go-core
- servlet
- Jackson
- MySQL
- java
- toby
- clean code
- programming
- db
- java8
- javascript
- Spring
- OOP
- code
- JPA
- 정규표현식
- JavaScript Core
- EffectiveJava
- TEST
- Kotlin
- DesignPattern
- http
- backend개발환경
- frontcode
- spring cloud
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |