【问题标题】:Where does Spring Boot define its default JSON date (i.e. LocalDateTime) format?Spring Boot 在哪里定义了其默认的 JSON 日期(即 LocalDateTime)格式?
【发布时间】:2017-12-21 22:20:06
【问题描述】:

使用返回 JSON 有效负载的 Spring Boot 创建 REST 服务时,Java 8 的 LocalDateTime 被序列化。格式字符串(即模式)在哪里定义(大概)Jackson 在将对象编组为字符串时应用,我在哪里可以找到 Spring Boot 中应用该格式的默认配置(即设置格式化程序)?

(注意:我可以在有效负载中看到格式化的日期,而不是时间戳。)

【问题讨论】:

  • LocalDateTime 不是时间戳,所以看不到时间戳是很正常的。也就是说,文档回答了您的问题:docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
  • 文档将我指向 Jackson2ObjectMapperBuilder,而后者又指向 JSR310Module 并通过...
  • ...LocalDateTimeSerializer 最后到LocalDateTime::toString。我的LocalDateTime 设置为1776-07-04T12:29Z,但我得到1776-07-04T12:29:00Z。文档说“使用的格式将是最短的......其中省略的部分暗示为零”:uuuu-MM-dd'T'HH:mm。为什么我会收到:00 回复?
  • LocalDateTime 没有时区。所以你不能有这样一个最终的 Z。如果你有,你可能实际上并没有序列化 LocalDateTime。 System.out.println(LocalDateTime.parse("1776-07-04T12:29")); 产生您期望的输出:1776-07-04T12:29

标签: spring spring-mvc spring-boot jackson


【解决方案1】:

Jackson2ObjectMapperBuilderregisterWellKnownModulesIfAvailable 注册多个模块的方法中执行相当棘手的逻辑。特别是对于 java 8 时间:

// Java 8 java.time package present?
if (ClassUtils.isPresent("java.time.LocalDate", this.moduleClassLoader)) {
    try {
        Class<? extends Module> javaTimeModule = (Class<? extends Module>)
                ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", this.moduleClassLoader);
        objectMapper.registerModule(BeanUtils.instantiateClass(javaTimeModule));
    }
    catch (ClassNotFoundException ex) {
        // jackson-datatype-jsr310 not available
    }
}

因此,如果您的应用程序依赖于jackson-datatype-jsr310 模块,spring 将静默注册它。结果,您将从此模块中获得用于 java 时间类型的专用序列化器/反序列化器。你对LocalDateTimeSerializer 很感兴趣。如您所见,序列化逻辑取决于useTimestamp,在您的情况下返回false,因此我们移至else 分支。默认情况下,_formatter 为 null,使用 _defaultFormatter(),即DateTimeFormatter.ISO_LOCAL_DATE_TIME。如果您想将日期序列化为字符串,或者通过从 useTimestamp 方法返回 true 来使用来自 if 分支的序列化逻辑,您可以通过提供自定义格式化程序轻松更新此行为。

@Override
public void serialize(LocalDateTime value, JsonGenerator g, SerializerProvider provider)
    throws IOException
{
    if (useTimestamp(provider)) {
        g.writeStartArray();
        g.writeNumber(value.getYear());
        g.writeNumber(value.getMonthValue());
        g.writeNumber(value.getDayOfMonth());
        g.writeNumber(value.getHour());
        g.writeNumber(value.getMinute());
        if (value.getSecond() > 0 || value.getNano() > 0) {
            g.writeNumber(value.getSecond());
            if(value.getNano() > 0) {
                if (provider.isEnabled(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS))
                    g.writeNumber(value.getNano());
                else
                    g.writeNumber(value.get(ChronoField.MILLI_OF_SECOND));
            }
        }
        g.writeEndArray();
    } else {
        DateTimeFormatter dtf = _formatter;
        if (dtf == null) {
            dtf = _defaultFormatter();
        }
        g.writeString(value.format(dtf));
    }
}

// since 2.7: TODO in 2.8; change to use per-type defaulting
protected DateTimeFormatter _defaultFormatter() {
    return DateTimeFormatter.ISO_LOCAL_DATE_TIME;
}

protected boolean useTimestamp(SerializerProvider provider) {
    if (_useTimestamp != null) {
        return _useTimestamp.booleanValue();
    }
    // assume that explicit formatter definition implies use of textual format
    if (_formatter != null) { 
        return false;
    }
    return provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

【讨论】:

    猜你喜欢
    • 2019-08-15
    • 1970-01-01
    • 2017-01-29
    • 2015-07-09
    • 2017-11-16
    • 2015-07-26
    • 1970-01-01
    • 2019-05-19
    相关资源
    最近更新 更多