๐ ๏ธ LocalDate/LocalDateTime ์ปค์คํ ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ: ๋ก์ผ์ผ ๊ธฐ๋ฐ ํฌ๋งท ์กฐ์
๊ฐ์
์งํ ์ค์ธ ํ๋ก์ ํธ์์ LocalDate, LocalDateTime ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ์ง๋ ฌํํ๊ณ ์ญ์ง๋ ฌํํ ๋, ๋ก์ผ์ผ์ ๋ง์ถ ํฌ๋งท์ ์ ์ฉํด์ผ ํ ํ์๊ฐ ์๊ฒผ๋ค. Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ Map์ ํ์ฉํ์ฌ LocalDate, LocalDateTime์ ํฌ๋งท์ ๋ก์ผ์ผ์ ๋ฐ๋ผ ์กฐ์ ํ๋ ์ปค์คํ ์ง๋ ฌํ๊ธฐ์ ์ญ์ง๋ ฌํ๊ธฐ๋ฅผ ๊ตฌํํด๋ณด์๋ค.
Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์
Jackson์ Java ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ์ง๋ ฌํํ๊ฑฐ๋ JSON์ Java ๊ฐ์ฒด๋ก ์ญ์ง๋ ฌํํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ฃผ์ ํด๋์ค ์ค ํ๋์ธ ObjectMapper๋ JSON ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ํต์ฌ ํด๋์ค์ด๋ค. ObjectMapper๋ ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ์ ๋ํ ์ค์ ์ ์กฐ์ ํ ์ ์๋ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, ์ปค์คํ ์ง๋ ฌํ๊ธฐ์ ์ญ์ง๋ ฌํ๊ธฐ๋ฅผ ์ฝ๊ฒ ๋ฑ๋กํ๊ณ ๊ด๋ฆฌํ ์ ์๋ค.
์ปค์คํ ์ง๋ ฌํ๊ธฐ ๋ฐ ์ญ์ง๋ ฌํ๊ธฐ ๊ตฌํ
DateTimeFormatterUtils ํด๋์ค
DateTimeFormatterUtils
ํด๋์ค๋ ๋ค์ํ ๋ก์ผ์ผ์ ๋ง์ถ DateTimeFormatter
๋ฅผ ๊ด๋ฆฌํ๋ค. ์ด ํด๋์ค๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตญ์ ํ ์๊ตฌ ์ฌํญ์ ๋ง๊ฒ ๋ ์ง์ ์๊ฐ ํฌ๋งท์ ๋์ ์ผ๋ก ์กฐ์ ํ๊ณ ์ ํ๋ค.
์ฌ์ฉํ ๋ Locale์ Key๋ก Map์ ํธ์ถํ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
public class DateTimeFormatterUtils {
private DateTimeFormatterUtils() { throw new IllegalStateException("Utility class");}
public static final Map<Locale, DateTimeFormatter> dateTimeFormatterMap =
Map.ofEntries(
Map.entry(Locale.KOREA, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
Map.entry(Locale.US, DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss")),
Map.entry(Locale.UK, DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")),
Map.entry(Locale.FRANCE, DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")),
Map.entry(Locale.GERMANY, DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")),
Map.entry(Locale.JAPAN, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")),
Map.entry(Locale.CHINA, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
);
public static DateTimeFormatter getDateTimeFormatter(Locale locale) {
return dateTimeFormatterMap.getOrDefault(locale, dateTimeFormatterMap.get(Locale.KOREA));
}
}
LocalDateTimeSerializer ํด๋์ค
LocalDateTimeSerializer
ํด๋์ค๋ LocalDateTime
๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํํ ๋, ๋ก์ผ์ผ์ ๋ง์ถ ํฌ๋งท์ ์ ์ฉํ๋ค. ์ด๋ฅผ ํตํด ์ฌ์ฉ์๋ณ๋ก ์ ์ ํ ํฌ๋งท์ ์ ๊ณตํ ์ ์๋ค. ํฌ๋งท ์ค์ ์ ์คํจํ ๊ฒฝ์ฐ, ๊ฐ์ ์ ์ ํ ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ค.
public class LocalDateTimeSerializer extends StdSerializer<LocalDateTime> {
public LocalDateTimeSerializer() {
super(LocalDateTime.class);
}
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
Locale locale = LocaleContextHolder.getLocale();
DateTimeFormatter formatter = DateTimeFormatterUtils.getDateTimeFormatter(locale);
try {
gen.writeString(value.format(formatter));
} catch (Exception e) {
throw new IOException("The format of the response for the datetime field is invalid.", e);
}
}
}
LocalDateTimeDeserializer ํด๋์ค
LocalDateTimeDeserializer
ํด๋์ค๋ JSON ๋ฌธ์์ด์ LocalDateTime
๊ฐ์ฒด๋ก ๋ณํํ ๋, ์ค์ ๋ ํฌ๋งท์ ์ ์ฉํ์ฌ ๋ณํํ๋ค. ์ด๋ฅผ ํตํด ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋ ๋ฐ์ดํฐ๊ฐ ์ ํจํ ํ์์ธ์ง ํ์ธํ ์ ์๋ค.
public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
public LocalDateTimeDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String dateTime = p.getText();
Locale locale = LocaleContextHolder.getLocale();
DateTimeFormatter formatter = DateTimeFormatterUtils.getDateTimeFormatter(locale);
try {
return LocalDateTime.parse(dateTime, formatter);
} catch (DateTimeParseException e) {
throw new InvalidRequestException("msg.valid.LocalDateTimeRange.field", "");
}
}
}
JacksonConfig ํด๋์ค
JacksonConfig
ํด๋์ค๋ ObjectMapper
๋ฅผ ์ค์ ํ์ฌ ์ปค์คํ
์ง๋ ฌํ๊ธฐ์ ์ญ์ง๋ ฌํ๊ธฐ๋ฅผ ๋ฑ๋กํ๋ค. ์ด๋ฅผ ํตํด ๋ชจ๋ JSON ๋ณํ ์์
์์ ์ผ๊ด๋ ๋ ์ง์ ์๊ฐ ํฌ๋งท์ ์ ์ฉํ ์ ์๋ค.
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDate.class, new LocalDateSerializer());
module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(module);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return objectMapper;
}
}
์ ์ฉ ๊ฒฐ๊ณผ
LocalDateTime
, LocalDate
๊ฐ์ฒด๋ฅผ ๋ก์ผ์ผ์ ๋ง์ถ ํฌ๋งท์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ๋์๋ค.
ํฌ๋งท ์ผ๊ด์ฑ ์ ์ง: ๋ค์ํ ๋ก์ผ์ผ์ ๋ง๋ ํฌ๋งท์ ์๋์ผ๋ก ์ ์ฉํจ์ผ๋ก์จ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์๋ค. ์ง๊ธ ํ๋ก์ ํธ์ฒ๋ผ ๋ค์ํ Locale ์ฌ์ฉ์๋ฅผ ๊ฐ์ง ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ์ฉํ ๊ฒ ๊ฐ๋ค.
ํ๋ก ํธ์๋์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ฐ์ํ: JSON ์๋ต์์ ๋ ์ง์ ์๊ฐ ์ ๋ณด๋ฅผ ์ผ๊ด๋๊ฒ ํ์ํจ์ผ๋ก์จ, ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ค์ด ๋ฐ์ดํฐ๋ฅผ ํ์ฑํ ํ์๊ฐ ์์ด์ ธ ์ข์ํ๋ค. ใ ใ
์ ์ง๋ณด์ ์ฉ์ด์ฑ: ํฌ๋งท ๋ณ๊ฒฝ์ด ํ์ํ ๋, ์ด ํ์ผ ํ๋๋ก ๋ณ๊ฒฝ์ ๊ด๋ฆฌํ๋ฉด ๋๋ค.
LocalDate, Time Formatter๋ ๋์ผํ ๋ก์ง์ผ๋ก ์์ฑํ๋ค! ์ ํธ์ฑ ํด๋์ค๋ฅผ ์ง์ ์์ฑํ๊ณ ๋ฐ์ํ ๊ฑด ๋ ์ฒ์์ธ ๊ฒ ๊ฐ์๋ฐ ๋์ค์ ํ๋ก์ ํธ์ ๋ ๋ง์ ๋ก์ผ์ผ์ ์ถ๊ฐํ๊ฑฐ๋ ํฌ๋งท์ ๋ณ๊ฒฝํด์ผ ํ ๊ฒฝ์ฐ์๋ ์ ์ฐํ๊ฒ ๋์ฒํ ์ ์์ง ์์๊น ์ถ๋ค.