SpringCloud 中 LocalDateTime 的实践

1,507 阅读3分钟

在 JDK 8 中 Date、Calendar 等类型已经不推荐使用,取而代之是全新的java.time包,但是在实际的使用中遇到一些问题,比如 SpringCloud 在使用 java.time 包时不太方便,主要在接收前端参数、返回数据以及 feign 调用传参时

时间传递

传递时间类型数据一般就两种方式

  • 时间格式的字符串
  • 时间戳 (13 位数值类型)

建议在任何场景下优先考虑时间戳 (13 位数值类型),具体分析参考 微服务中时间传递的最佳实践

接收前端时间类型参数

在 Spring 中接收前端时间类型参数有以下注意点

  1. spring 默认使用 Jackson 作为 json 的序列化反序列化工具
  2. 只有前端传参使用 json 格式(Content-Type : application/json),并放在 body 体中时,sping 才会使用 Jackson 将传参反序列化成对象
  3. 当参数作为 url 的一部分,或者拼接在 url 后面,或者通过表单提交时,并不属于 json 格式(Content-Type : application/json),spring 不会使用 Jackson 将参数反序列化成对象,而是使用自己的解析方法转换参数

所以处理前端传递的时间类型数据时,也要两种情况

  • 通过 json (Content-Type : application/json) 传递时间类型数据
  • 通过其他方式传递时间类型数据

通过 json (Content-Type : application/json) 传递时间类型数据

使用这种方式传递时间类型数据时,可以通过自定义 Jackson 反序列化器,把传入的时间类型数据转换成任意类型。

以时间戳为例,把时间戳转换成 LocalDateTime ,只需要自定义一个反序列化器,比如叫 TimestampDeserializerLocalDateTime ,然后再需要转换的字段上添加 @JsonDeserialize(using = TimestampDeserializerLocalDateTime.class)

详情请参考 自定义 Jackson 序列化反序列化器

通过其他方式传递时间类型数据

主要包括

  • 参数作为 url 的一部分,在 spring 中使用 @PathVariable() 来接收
  • 参数以?拼接在 url 后面,一般是 get 请求
  • 参数通过表单提交,多见于 post 请求

这种需要走 Spring 自己的解析方法,我们可以通过 @bean 的方式,覆盖默认的方法

例如将时间戳转换成 LocalDateTime

package com.cusc.its.bussinessservicezx.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.Formatter;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

@Configuration
public class LocalDateTimeConfig {
    @Bean
    public Formatter<LocalDateTime> localDateTimeFormatter() {
        return new Formatter<LocalDateTime>() {
            @Override
            public LocalDateTime parse(String text, Locale locale) {
                return Instant
                        .ofEpochMilli(Long.parseLong(text))
                        .atZone(ZoneId.systemDefault())
                        .toLocalDateTime();
            }

            @Override
            public String print(LocalDateTime object, Locale locale) {
                return DateTimeFormatter.ISO_DATE.format(object);
            }
        };
    }
}

返回时间类型的数据给前端

怎么接收前端传递的时间类型数据说完了,现在说下怎么返回时间类型的数据。

没有特殊说明的情况下,后端普遍都是返回 json 格式的数据给前端,java的对象类型会被 Jackson 序列化成 json。

虽然常用的类 Jackson 都提供了对应的序列化器,但有时候序列化的结果并不是我们需要的。这时候我们就需要根据返回的数据格式,自定义自己的序列化器。

返回的数据格式

返回时间类型的数据,一般也是两种格式

  • 时间格式的字符串
  • 时间戳 (13 位数值类型)

同样,建议优先选择时间戳 (13 位数值类型)

自定义序列化器

假设字段类型为 LocalDateTime 要返回的时间类型为时间戳,则我们需要定义一个 LocalDateTime转时间戳的序列化器,具体操作和使用参考 自定义 Jackson 序列化反序列化器