Skip to content
정명주(myeongju.jung) edited this page Apr 30, 2018 · 2 revisions

JSR310

java8에는 새로운 날짜, 시간 형식이 추가됨.

  • LocalDateTime, LocalDate, LocalTime
  • OffsetDateTime, ZonedDateTime
  • Instant, Duration, Clock, Period, ZonedOffset
  • Chronology, ChronoLocalDate, ChronoLocalDate, ChronoZonedDateTime

참고 : http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html

기존의 날짜형식인 Date, Calendar 이 잘 알다시피 여러가지 설계적인 문제점이 존재하고 있었는데 그것을 해결하고자 함 그런데 신규 스팩이다 보니 여러 라이브러리나 프레임워크에서 기본 지원이 안되는 경우가 많음. 고로 이러한 부분을 직접 해결하거나 다른 방식으로 풀어야 함

JPA & HIbernate

AS-IS

@Entity
@Getter
@EqualsAndHashCode
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Entity {
    @Id
    @GeneratedValue
    private Long seq;
 
    @Column(length = 200, nullable = false)
    private String title;
 
    @Lob
    @Column
    private String content;
 
    @Column(nullable = false, insertable = false)
    @ColumnDefault("0")
    private int hit;
 
    @Column(nullable = false, insertable = false)
    @ColumnDefault("CURRENT_TIMESTAMP")
    @Temporal(Date) // Temporal 설정이 요구됨
    private Date createdAt;
}

TO-BE

최소 hibernate 5.x 이상이 요구

@Entity
@Getter
@EqualsAndHashCode
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Entity {
    @Id
    @GeneratedValue
    private Long seq;
 
    @Column(length = 200, nullable = false)
    private String title;
 
    @Lob
    @Column
    private String content;
 
    @ColumnDefault("0")
    @Column(nullable = false, insertable = false)
    private int hit;
 
    @ColumnDefault("CURRENT_TIMESTAMP")
    @Column(nullable = false, insertable = false)
    private ZonedDateTime createdAt;
}

JSON

상호 간 API를 요청, 응답 시 내부적으로 날짜시간 타입을 timestamp-milliseconds(long, 이하 timeMillis) 형으로 통신한다고 가정

Server(Serializer)

  • 기본 설정이 timestamp-nanoseconds 이기 때문에 변경이 요망

application.yml

spring:
  jackson:
    serialization:
      write-date-timestamps-as-nanoseconds: false

Client (Deserializer)

역직렬화 하는 클라이언트 입장에서는 단순 설정만으로는 해결이 불가능 그래서 직접 jackson Deserializer 인터페이스를 구현하는 커스텀 역직렬화 컴포넌트를 제공하고 해당 설정을 기본으로 올려야함

ZonedDateTimeDeserizlizer.java

public class ZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {
 
    public ZonedDateTimeDeserializer() {
        super(ZonedDateTime.class);
    }
 
    @SuppressWarnings("DuplicateThrows")
    @Override
    public ZonedDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        long timeMillis = jp.getLongValue();
        if (timeMillis == 0) {
            return null;
        }
        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), ZoneId.systemDefault());
    }
}

CustomerJsonComponent.java

@JsonComponent
class CustomerJsonComponent {
    public static class DefaultZonedDateTimeDeserializer extends ZonedDateTimeDeserializer {
        private static final long serialVersionUID = 3414058555754703366L;
    }
}

FreeMarker

기본적으로 FreeMarker에서 JSR310 에 관련한 타입을 지원하지 않음!!! 오픈소스가 있어서 그것을 이용하는 것으로 결정

build.gradle

compile "no.api.freemarker:freemarker-java8:$freemarkerJava8Version"

FreeMarkerConfiguration.java

@Configuration("freeMarkerCustomConfiguration")
@Slf4j
public class FreeMarkerConfiguration {
    @Autowired
    private freemarker.template.Configuration freeMarkerConfiguration;
 
    @PostConstruct
    public void postConstruct() {
        log.info("FreeMarkerConfiguration.postConstruct");
        // freeMarker java8 타입 지원 설정
        freeMarkerConfiguration.setObjectWrapper(new Java8ObjectWrapper(freemarker.template.Configuration.VERSION_2_3_26));
    }
}

Usage

sample.ftl

<tbody>
    <#list samples as sample>
    <tr>
        <td class="text-right">${sample.seq}</td>
        <td><a href="/samples/${sample.seq}">${sample.title}</a></td>
        <td>${sample.content}</td>
        <td class="text-right">${sample.hit}</td>
        <!-- 아래와 같이 zonedDateTimeObj.format(formatString) 형태로 사용하면됨 -->
        <td class="text-center">${sample.createdAt.format("yyyy.MM.dd HH:mm:ss")}</td>
    </tr>
    </#list>
    <#if !samples?has_content>
    <tr>
        <td colspan="5">표시할 정보가 존재하지 않습니다.</td>
    </tr>
    </#if>
</tbody>
Clone this wiki locally