스프링 백엔드 도메인에서 날짜 관련 필드를 ZoneDateTime을 사용하고 있다.
처음 API 설계시 front에서 날짜관련 필드 API요청을 yyyymmdd 포맷으로 전송하기 때문에
requestDto, responseDto에 있는 날짜 관련 필드를 String으로 정의했다.
이게 별로 맘에 안들어서 String을 ZoneDateTime으로 변경하기로 했다.
HTTP 바디 적용
serialize
responseDto에 필드위에 @JsonFormat 애노테이션으로 쉽게 변경가능하다
deseirialize
requestDto는 날짜가 바디에 있는 경우 HTTP 메시지 converter가 변환해주고
requestParam의 경우 Argument Resolver가 변환해 주는데
custom deserializer 추가하면
argumentResolver에서 결국 추가한 objectMapper deserializer를 참고하여 처리할 것이라고 생각한다.
argumentResolver에서는 resolveArgument 함수가 있고 파라미터로 WebDataBindFactory를 넘기는데,
Data를 바인딩하면서 @JsonDeserialize 어노테이션을 확인하고 stdDeserializer를 상속받은 클래스를 적용할 것 같다.
기존에 잘못 가정했던 부분을 취소선으로 그었다.
Deserializer는 HTTP 컨버터에서만 작동하고 쿼리 파라미터에서는 변환이 되지 않는다.
HTTP 컨버터에서 objectMapper로 매핑하는 과정중에만 동작하는 것 같다.
Get의 query 파라미터 위해서는 Formatter를 추가해야 한다.
String to LocalDateTime의 경우는 @DateTimeFormat로 변환 가능하다.
구현 후
RequestDto
public class RequestDto {
@JsonDeserialize(using = ZonedDateTimeDeserializerStart.class)
private ZonedDateTime startDate;
@JsonDeserialize(using = ZonedDateTimeDeserializerEnd.class)
private ZonedDateTime endDate;
}
ZoneDateTimeDeserializerStart
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.time.ZonedDateTime;
public class ZonedDateTimeDeserializerStart extends StdDeserializer<ZonedDateTime> {
public ZonedDateTimeDeserializerStart(){
super(ZonedDateTime.class);
}
@Override
public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
String value = p.readValueAs(String.class);
return TimeUtils.yyyymmddToZdt(value);
}
}
ZoneDateTimeDeserializerEnd
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.time.ZonedDateTime;
public class ZonedDateTimeDeserializerEnd extends StdDeserializer<ZonedDateTime> {
public ZonedDateTimeDeserializerEnd(){
super(ZonedDateTime.class);
}
@Override
public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
String value = p.readValueAs(String.class);
return TimeUtils.yyyymmddToZdtEnd(value);
}
}
장점
- dto안의 날짜필드를 ZoneDateTime으로 통일성 있게 가져갈 수 있다.
- Repository에 있던 TimeUtils를 Deserializer로 빼서 코드가 깔끔해졌다.
//querydsl
//변경 전
task.createDate.between(TimeUtils.yyyymmddToZdt(searchCondition.getStartDate())
, TimeUtils.yyyymmddToZdtEnd(searchCondition.getEndDate()))
//변경 후
task.createDate.between(searchCondition.getStartDate(), searchCondition.getEndDate())
단점
- 각 Test 코드에 TimeUtils를 적용해야 해서 조금 지저분해짐
class BusinessTest{
...
//변경 전
SearchCondition searchCondition = SearchCondition.builder()
.startDate("20211207")
.endDate("20220307")
//변경 후
SearchCondition searchCondition = SearchCondition.builder()
.startDate(TimeUtils.yyyymmddToZdt("20211207"))
.endDate(TimeUtils.yyyymmddToZdt("20220307"))
}
쿼리 파라미터 적용
- 스프링에서 제공하는 @DateTimeFormat은 String을 LocalDateTime으로 변환은 해주지만 ZoneDateTime으로는 변환해 주지 못한다.
- 그렇기 때문에 Custom Formatter를 추가해주어야 한다.
먼저 Fomatter를 추가해보자.
public class StringToZdtFormatter implements Formatter<ZonedDateTime> {
@Override
public ZonedDateTime parse(String text, Locale locale) throws ParseException {
return TimeUtils.yyyymmddToZdtEnd(text);
}
@Override
public String print(ZonedDateTime object, Locale locale) {
return TimeUtils.zdtToyyyymmdd(object);
}
}
WebMvcConfigurer에 Custom Formatter를 추가
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new StringToZdtFormatter());
}
}
이제 내가 원했던 대로 모든 계층에서 날짜를 ZoneDateTime으로 통일할 수 있게 되었다.
참고
https://d2.naver.com/helloworld/0473330
'Back-End > SpringBoot' 카테고리의 다른 글
Failed to resolve org.junit.platform:junit-platform-launcher (0) | 2022.01.03 |
---|---|
네이버 OAuth 2.0 로그인 설정 (0) | 2020.04.30 |
구글 OAuth 2.0 로그인 설정 (0) | 2020.04.30 |
인텔리제이 설치 (0) | 2020.04.24 |