Spring을 사용하여 개발 할 경우 Controller에서 요청 과 응답을 주고 받을 때
DTO에서 LocalDate와 LocalDateTime을 사용할 경우가 종종 있습니다.
이때 직렬화를 하지 못해 String으로 받은 후 서비스 레이어에서 혹은 DB에 저장하기 직전에 변환하는 경우가 있습니다.
Spring에선 굳이 이럴 필요가 없으니 아래 내용을 토대로 번거로운 과정을 생략해보면 좋을 것 같습니다.
우선적으로 정답을 말씀드리면 @JsonFormat 어노테이션과 @DateTimeForamt을 사용하면 가능합니다.
1. RequestParameter
1-1. @ModelAttribute
Controller 코드
@GetMapping("/get")
public String get(GetModel getModel) {
log.info("get 요청 데이터 = {}", getModel);
return "get 성공";
}
GetModel 코드
@ToString
@Getter
@Setter
@NoArgsConstructor
public class GetModel {
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime requestDateTime;
}
이를 통해, @ModelAttribute에서 날짜 직렬화가 필요할 경우 @DateTimeFormat을 사용하면 된다는 것을 확인하였습니다.
1-2. @RequestParameter
Controller 코드
@GetMapping("/requestParameter")
public String requestParameter(
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
@RequestParam("requestDateTime") LocalDateTime requestDateTime) {
log.info("requestParameter 요청 데이터 = {}", requestDateTime);
return "requestParameter 성공";
}
Test 코드 및 실행 결과
@RequestParamter 역시 날짜 직렬화가 필요할 경우 @DateTimeFormat을 사용하면 가능합니다.
2. RequestBody
이번엔 Post 요청시 직렬화에 대해 알아보도록 하겠습니다.
Controller 코드
@PostMapping("/post")
public String post(@RequestBody JsonModel jsonModel) {
log.info("get 요청 데이터 = {}", jsonModel);
return "post 성공";
}
JsonModel 코드
@ToString
@Getter
@Setter
@NoArgsConstructor
public class JsonModel {
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime requestDateTime;
}
@ToString
@Getter
@Setter
@NoArgsConstructor
public class JsonModel {
private String name;
// @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime requestDateTime;
}
Test 결과
Post로 보내는 Request Body (JSON 객체)는 @DateTimeFormat과 @JsonFormat 모두 사용할 수 있습니다.
JsonFormat 과 DateTimeFormat의 우선순위는 아래와 같습니다.
- 두 어노테이션 모두가 있으면 @JsonFormat이 진행된다
- @JsonFormat이 틀리면 @DateTimeFormat이 맞더라도 직렬화는 실패한다
- 단, @DateTimeFormat이 있다면 @DateTimeFormat의 포맷으로 직렬화가 진행된다.
3. ResponseBody
Controller 코드
@GetMapping("/response")
public ResponseModel responseModel() {
return new ResponseModel("jojoldu", LocalDateTime.of(2018,12,15,10,0,0));
}
ReponseModel 코드
@Getter
@RequiredArgsConstructor
public class ResponseModel {
private final String name;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
private final LocalDateTime requestDateTime;
}
테스트 수행 결과
@ResponseBody 에서는 @JsonFormat 만 가능합니다. @DateTimeFromat의 경우 오류를 발생시킵니다.
4. @DateTimeFormat vs @JsonFormat
@JsonFormat은 Jackson의 어노테이션이고, @DateTimeFormat은 Spring의 어노테이션입니다.
@JsonFormat은 LocalDate 혹은 LocalDateTime을 JSON으로 직렬화할때 포맷을 관리합니다.
Spring의 기본 JSON 컨버터는 Jackson입니다.
그러다보니 JSON으로 변환을 할때 Jackson을 통해서 진행됩니다.
만약 JSON 직렬화 과정에서 @JsonFormat이 없다면 Spring에서는 @DateTimeFormat를 통해 직렬화를 진행합니다.
반면 Jackson은 Spring의 어노테이션인 @DateTimeFormat 을 사용하지 못합니다.
그래서 @DateTimeFormat을 지정했다 하더라도, Jackson은 이 어노테이션을 전혀 고려하지 않고 JSON 직렬화을 진행합니다.
JSON 직렬화 외에는 Jackson이 사용되지 않기 때문에 @JsonFormat은 효과가 없습니다.
그래서 RequestParameter나 ModelAttribute에선 @DateTimeFormat 만 적용될 수 있습니다.
Conclusion
다음과 같은 결론을 얻을 수 있습니다.
- Get요청시에 @ModelAttribute, @RequestParam은 @DateTimeFormat
- Get 요청시 응답으로 받을 때 @JsonFormat
- Post 요청 시 RequestBody 에서는 @DateTimeFormat, @JsonFormat 둘다 가능
- Post 요청, ResponseBody에서는 @JsonFormat
- Post 요청시에도 @DateTimeFormat이 적용될 수 있으나, @JsonFormat이 지정되어 있지 않을때만 가능하다.
참고:
https://jojoldu.tistory.com/361
SpringBoot에서 날짜 타입 JSON 변환에 대한 오해 풀기
안녕하세요? 이번 시간엔 Spring과 JSON에 대해 정리해보려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. (공부한 내용을 정리하는 Github와 세미나+책 후
jojoldu.tistory.com
'BackEnd > SpringBoot' 카테고리의 다른 글
Spring Transaction 에 대한 이해 (0) | 2023.09.20 |
---|---|
[Spring] 어노테이션의 정의와 동작원리 (0) | 2023.09.18 |
스프링 부트 로컬 캐시 적용하기 (0) | 2023.06.25 |
Feign Client 를 활용하여 외부통신 연동하기 (0) | 2023.04.22 |
SpringBoot @Converter @Convert 데이터 처리 시 활용 (1) | 2022.12.11 |