2016년 7월 8일 금요일

spring boot mvc에서 java 8 date 객체 json 처리하기

spring mvc를 사용하면 date 객체를 주고받는 형태에 대해 고민을 하게 된다.

특히 java 8의 date 객체들을 쓰게 되면 더더욱 그렇다.


응답 처리


java 8의 LocalDateTime이나 LocalDate를 사용하면 응답하는 MappingJackson2JsonView의 기본 json 결과는 다음과 같다.
{ "localDateSample" : [2016,7,8], "localDateTimeSample" : [2016,7,1,0,0] }


serialized as numeric timestamps 형태로 년월일 / 년월일시분 값을 넘겨주는데 이런 형태로 응답하면 client의 javascript 객체에서 변환해서 쓸 때 불편한 점이 많다.

date format string 을 넘겨받아 사용하는게 더 사용하기 편하다고 생각을 해서 다음과 같이 boot properties 설정을 한다.
# response datetime 처리 설정
spring.jackson.serialization.write-dates-as-timestamps=false


위와 같이 설정을 하면 응답처리는 다음과 같이 된다.
{ "localDateSample" : "2016-07-08", "localDateTimeSample" : "2016-07-31T00:00" }

이렇게 사용하면 javascript에서 사용하기가 편해지고 timezone 설정이 들어간 경우도 moment.js 와 같은 라이브러리를 사용하면 쉽게 사용할 수 있다.


요청 처리


위와 같이 설정하는 경우 응답에 대해서 처리는 되었지만 요청이 온 경우에 대해서도 처리를 해주어야 한다.
요청에 대해 date format string 을 넘겨받는 설정은 WebMvcConfigurerAdapter에 다음과 같이 선언을 해준다.
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    ...

    // request date conversion 처리
    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}


여기까지 설정을 하면 @ResponseBody로 리턴되는 produces = MediaType.APPLICATION_JSON_VALUE 응답처리에 올바르게 적용된다.
하지만 html, json에 대한 contentNegotiation 처리에도 올바른 응답을 처리하기 위해선 WebMvcConfigurerAdapter에 다음과 같이 선언해야한다.
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    ...

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.viewResolver(thymeleafViewResolver);  // thymeleaf를 쓰는 경우
        registry.enableContentNegotiation(new MappingJackson2JsonView(objectMapper));
    }
}


위에서 중요한 핵심은 objectMapper를 spring boot에서 생성한 것을 써야한다는 점이다. 만약 new MappingJackson2JsonView() 로 생성한다면 spring boot 설정으로 선언한 objectMapper가 아닌 spring web의 Jackson2ObjectMapperBuilder로 생성한 objectMapper를 사용하기 때문에 jackson 설정이 동작하지 않는다.

댓글 없음:

댓글 쓰기