JSR310 Guide - redutan/redutan.github.io GitHub Wiki
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 μ΄ μ μλ€μνΌ μ¬λ¬κ°μ§ μ€κ³μ μΈ λ¬Έμ μ μ΄ μ‘΄μ¬νκ³ μμλλ° κ·Έκ²μ ν΄κ²°νκ³ μ ν¨ κ·Έλ°λ° μ κ· μ€ν©μ΄λ€ 보λ μ¬λ¬ λΌμ΄λΈλ¬λ¦¬λ νλ μμν¬μμ κΈ°λ³Έ μ§μμ΄ μλλ κ²½μ°κ° λ§μ. κ³ λ‘ μ΄λ¬ν λΆλΆμ μ§μ ν΄κ²°νκ±°λ λ€λ₯Έ λ°©μμΌλ‘ νμ΄μΌ ν¨
@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;
}
μ΅μ 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;
}
μνΈ κ° APIλ₯Ό μμ², μλ΅ μ λ΄λΆμ μΌλ‘ λ μ§μκ° νμ μ
timestamp-milliseconds
(long, μ΄ν timeMillis) νμΌλ‘ ν΅μ νλ€κ³ κ°μ
- κΈ°λ³Έ μ€μ μ΄
timestamp-nanoseconds
μ΄κΈ° λλ¬Έμ λ³κ²½μ΄ μλ§
application.yml
spring:
jackson:
serialization:
write-date-timestamps-as-nanoseconds: false
μμ§λ ¬ν νλ ν΄λΌμ΄μΈνΈ μ μ₯μμλ λ¨μ μ€μ λ§μΌλ‘λ ν΄κ²°μ΄ λΆκ°λ₯ κ·Έλμ μ§μ 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μμ 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));
}
}
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>