๐Ÿ› ๏ธ 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 ๊ฐ์ฒด๋ฅผ ๋กœ์ผ€์ผ์— ๋งž์ถ˜ ํฌ๋งท์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

  1. ํฌ๋งท ์ผ๊ด€์„ฑ ์œ ์ง€: ๋‹ค์–‘ํ•œ ๋กœ์ผ€์ผ์— ๋งž๋Š” ํฌ๋งท์„ ์ž๋™์œผ๋กœ ์ ์šฉํ•จ์œผ๋กœ์จ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•œ Locale ์‚ฌ์šฉ์ž๋ฅผ ๊ฐ€์ง„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์œ ์šฉํ•  ๊ฒƒ ๊ฐ™๋‹ค.

  2. ํ”„๋ก ํŠธ์—”๋“œ์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ฐ„์†Œํ™”: JSON ์‘๋‹ต์—์„œ ๋‚ ์งœ์™€ ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ํ‘œ์‹œํ•จ์œผ๋กœ์จ, ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ ธ ์ข‹์•„ํ–ˆ๋‹ค. ใ…Žใ…Ž

  3. ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ: ํฌ๋งท ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ, ์ด ํŒŒ์ผ ํ•˜๋‚™๋กœ ๋ณ€๊ฒฝ์„ ๊ด€๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.

LocalDate, Time Formatter๋„ ๋™์ผํ•œ ๋กœ์ง์œผ๋กœ ์ž‘์„ฑํ–ˆ๋‹ค! ์œ ํ‹ธ์„ฑ ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ณ  ๋ฐ˜์˜ํ•œ ๊ฑด ๋˜ ์ฒ˜์Œ์ธ ๊ฒƒ ๊ฐ™์€๋ฐ ๋‚˜์ค‘์— ํ”„๋กœ์ ํŠธ์— ๋” ๋งŽ์€ ๋กœ์ผ€์ผ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ํฌ๋งท์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๊ฒฝ์šฐ์—๋„ ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค.


ยฉ 2022. All rights reserved.

Powered by Hydejack v9.1.6