LocalDateTime作为入参和返参的序列化问题

我们都知道LocalDatetime、LocalDate以及LocalTime,是JDK8 新增的和时间相关的类。在SpringBoot的创建接口的时候,可能需要将Local的相关时间类作为参数,但是有时候需要特输的时间格式,由于SpringBoot默认使用Jackson作为序列化的框架,所以在配置LocalDatetime这类新的API的时候,默认的参数就非常得让人不爽。经过一段折腾,笔者找到合适的解决方法,这里提供了一个简单地方法,将相应的时间转换为ISO8601的时间格式,保存了时区信息,同时接受参数也可以包含时区信息,或者自定义为前端需要的格式。

主要的点就是:

  1. 配置一些Bean用于将字符串转换为LocalDatetime类,也就是反序列化的配置
  2. 配置ObjectMapper,用户序列化的配置

依赖

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;
  }
}

代码很简单, 这里不再赘述,稍微看下就明白了了,需要注意的是:

  1. Converter<String, LocalDateTime> 实现的时候 不要简写为Lambda表达式,会报错,这是因为丢失类型信息导致的转换失败;
  2. 这里仅仅实现了我自己的需要的转换关系,若是没有需要,可以尝试对应写一下;
  3. 一定要保证这个类被扫描到;
  4. 各个实现的逻辑不通,可以自己根据自己的需求实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值