SpringBoot中LocalDatetime作為參數和返回值的序列化問題


👆關注微信公眾號,獲取更多編程內容


歡迎訪問我的個人網站 https://www.zhoutao123.com

本文原文地址 https://www.zhoutao123.com/#/blog/article/59

LocalDatetime、LocalDate以及LocalTime,是JDK8 新增的和時間相關的類。在SpringBoot的創建接口的時候,可能需要將Local的相關時間類作為參數,但是有時候需要特輸的時間格式,由於SpringBoot默認使用Jackson作為序列化的框架,所以在配置LocalDatetime這類新的API的時候,默認的參數就非常得讓人不爽。經過一段折騰,筆者找到合適的解決方法,這里提供了一個簡單地方法,將相應的時間轉換為ISO8601的時間格式,保存了時區信息,同時接受參數也可以包含時區信息,或者自定義為前端需要的格式。

Ps: 當然可以使用@JsonFormat等注解標識,但是能統一處理為什么還要單獨一個一個加那么麻煩呢?

主要的點就是:

  • [x] 配置一些Bean用於將字符串轉換為LocalDatetime類,也就是反序列化的配置
  • [x] 配置ObjectMapper,用戶序列化的配置

筆者建議,在項目中創建一個名為 LocalDatetimConfig.java的類用戶集中配置.

依賴

  • Grale
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8'
  • Maven
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.8</version>
</dependency>

代碼如下

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;

/** Converter 不可優化使用Lambda表達式,否則會出現啟動失敗的問題 */
@Configuration
public class LocalDateTimeSerializerConfig {

  /** String --> LocalDate */
  @Bean
  public Converter<String, LocalDate> localDateConverter() {
    return new Converter<String, LocalDate>() {
      @Override
      public LocalDate convert(@NotNull String source) {
        if (StringUtils.hasText(source)) {
          return LocalDate.parse(source, DateTimeFormatter.ISO_OFFSET_DATE);
        }
        return null;
      }
    };
  }

  /** String --> LocalDatetime */
  @Bean
  public Converter<String, LocalDateTime> localDateTimeConverter() {
    return new Converter<String, LocalDateTime>() {
      @Override
      public LocalDateTime convert(@NotNull String source) {
        if (StringUtils.hasText(source)) {
          return LocalDateTime.parse(source, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        }
        return null;
      }
    };
  }

  /** String --> LocalTime */
  @Bean
  public Converter<String, LocalTime> localTimeConverter() {
    return new Converter<String, LocalTime>() {
      @Override
      public LocalTime convert(@NotNull String source) {
        if (StringUtils.hasText(source)) {
          return LocalTime.parse(source, DateTimeFormatter.ISO_OFFSET_TIME);
        }
        return null;
      }
    };
  }

  /** Json序列化和反序列化轉換器,用於轉換Post請求體中的json以及將我們的對象序列化為返回響應的json */
  @Bean
  public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

    // LocalDateTime系列序列化模塊,繼承自jsr310,我們在這里修改了日期格式
    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(
        LocalDateTime.class,
        new JsonSerializer<LocalDateTime>() {
          @Override
          public void serialize(
              LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
              throws IOException {
            String format =
                value.atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
            gen.writeString(format);
          }
        });

    javaTimeModule.addSerializer(
        LocalDate.class,
        new JsonSerializer<LocalDate>() {
          @Override
          public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers)
              throws IOException {
            String format = value.format(DateTimeFormatter.ISO_OFFSET_DATE);
            gen.writeString(format);
          }
        });

    objectMapper.registerModule(javaTimeModule);
    return objectMapper;
  }
}

代碼很簡單, 這里不再贅述,稍微看下就明白了了,需要注意的是:

  • [x] Converter<String, LocalDateTime> 實現的時候 不要簡寫為Lambda表達式,會報錯,這是因為丟失類型信息導致的轉換失敗。
  • [x] 這里僅僅實現了我自己的需要的轉換關系,若是沒有需要,可以嘗試對應寫一下
  • [x] 一定要保證這個類被掃描到
  • [x] 各個實現的邏輯不通,可以自己根據自己的需求實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM