BackEnd/SpringBoot

String 형태가 아닌 LocalDateTime그대로 받아보자!

hyunki.Dev 2023. 1. 1. 19:15

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;
}

 

Test 코드 작성후 실행하였을 때 성공

 

이를 통해, @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 코드 및 실행 결과

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 결과

JsonFormat 과 DateTimeformat 모두에서 테스트 결과는 통과됩니다.

 

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