java Sping Boot Jackson日期格式

f1tvaqid  于 2023-05-12  发布在  Java
关注(0)|答案(2)|浏览(145)

我在SpringBoot遇到了Jackson的问题。我的控制器以yyyy-MM-dd'T'HH:mm:ss'Z'返回日期,但我需要yyyy-MM-dd'T'HH:mm:ss.SSS'Z'(用于使用date-fns库的angular中的mwl-calendar)。
控制器:

@GetMapping(value = "/slots", produces = MediaType.APPLICATION_JSON_VALUE)
public Set<SlotResponse> timeSlots() {
    return slotService.getSlots();
}

插槽响应:

@Data
public class SlotResponse {
    private Instant start;
    private Instant end;
}

其他依赖性:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

我试过:
1.使用@JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")注解
1.使用spring.jackson.date-format=yyyyMMddTHH:mm:ss.SSSZ配置
1.要手动创建ObjectMapper,请执行以下操作:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
    return mapper;
}

1.启用选项SerializationFeature.WRITE_DATES_WITH_ZONE_IDSerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE
但这一切都没有发生作用。每次看到这个结果:

[{"start":"2023-05-11T16:00:00Z","end":"2023-05-11T17:00:00Z"}]

我使用Java 17,SpringBoot 2.7.0,Jackson2.13.3
怎么了?

6rqinv9w

6rqinv9w1#

您可以为Instant类型创建自定义json序列化器:

public static class InstantSerializer extends StdSerializer<Instant> {

        public InstantSerializer() {
            super(Instant.class);
        }

        @Override
        public void serialize(
            @Nullable final Instant value,
            @NonNull final JsonGenerator jsonGenerator,
            @NonNull final SerializerProvider serializerProvider
        ) throws IOException {
            if (value != null) {
                final DateTimeFormatter formatter = DateTimeFormatter
                    .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                    .withZone(ZoneId.systemDefault());
                final String text = formatter.format(value);
                jsonGenerator.writeString(text);
            }
        }

    }

然后在您要遵循格式的字段上使用它:

@Data
    public class SlotResponse {

        @JsonSerialize(using = InstantSerializer.class) // Add this
        
        private Instant start;
        @JsonSerialize(using = InstantSerializer.class) // Add this
        private Instant end;
    }

如果你想让它应用于你的整个系统,你可以将序列化器添加到Jackson:

@Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        ...
        final SimpleModule module = new SimpleModule();
        module.addSerializer(new InstantSerializer());
        mapper.registerModule(module);
        ...
        return mapper;
    }
ercv8c1e

ercv8c1e2#

抱歉,无法复制

与(only

  • spring-boot-starter-web:2.7.0
  • Lombok岛
  • (dev tools,spring-boot-starter-test)

,(简称)“dto”:

package com.example.soq76225352;

import java.time.Instant;
import lombok.Data;

@Data
public class SomeResponse {
  private Instant start = Instant.now();
}

以及:

@RestController
class DemoController {

  @GetMapping(value = "/slots")
  public SomeResponse timeSlots() {
    return new SomeResponse();
  }
}

(no其他设置,属性,只有默认值..),我们得到:

{"start":"2023-05-11T09:08:23.569050400Z"}

这看起来非常像所需的格式。(??)
我一加:

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

,我得到:

2023-05-11 11:03:49.487  WARN 3732 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver :
   Resolved [org.springframework.http.converter.HttpMessageNotWritableException:
     Could not write JSON: Unsupported field: YearOfEra; nested exception is com.fasterxml.jackson.databind.JsonMappingException:
       Unsupported field: YearOfEra (through reference chain: 
         com.example.soq76225352.SomeResponse["start"])
   ]

(-> /error -> 404)!?

深入

  • 格式'Z'表示“文字Z”
  • Z指的是“区域偏移”(格式为+HHMM,请参见DateTimeFormatterBuilder+源文档)
  • 另一方面:X是“区域偏移”(如Z所述)或(文字)'Z'(如果是“零偏移”/UTC!DateTimeFormatter:)

实现方法:

  • 在所有情况下(这是奇怪的字面情况!),我们必须:
  • @JsonFormat(timezone = "..." //,...
  • spring.jackson.time-zone

...(显式)设置“config time zone”,参见Set Jackson Timezone for Date deserialization

  • 此外,我们需要确保(默认情况下):spring.jackson.serialization.WRITE_DATES_WITH_CONTEXT_TIME_ZONE=true,参见源代码(您的版本)
给定(例如)
spring.jackson.time-zone=UTC
何时/然后
  • 当格式为'Z'时,则得到"...Z"
  • 当格式为Z时,则得到"...+0000"
  • 当格式为X时,我们(也)得到"...Z"

相关,但旧:

相关,但不够深入/精确(毫秒):

相关问题