@JsonFormat失效,被jackson自定义配置覆盖

jackson配置类

我的jackson配置类如下,其中serializerByType(LocalDateTime.class, new LocalDateTimeSerializer()) 覆盖了@JsonFormat注解

@Configuration
public class JacksonConfiguration {

    public static final DateTimeFormatter optionalDateTimePattern =
        (new DateTimeFormatterBuilder()).appendValue(ChronoField.YEAR, 4)
            .appendPattern("[-][/]MM[-][/]dd['T'][ ]HH[:]mm[:][ss][,SSS][.SSS]").toFormatter();;
    static final ZoneOffset zoneOffset = OffsetDateTime.now(ZoneId.systemDefault()).getOffset();

    public JacksonConfiguration() {}

    /**
     * 配置和创建ObjectMapper对象
     */
    public static Jackson2ObjectMapperBuilder createJackson2ObjectMapperBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        return customizeBuilder(builder).serializerByType(LocalDateTime.class, new LocalDateTimeSerializer());
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return (builder) -> {
            // serializerByType(LocalDateTime.class, new LocalDateTimeSerializer()) 覆盖了@JsonFormat注解
            customizeBuilder(builder).serializerByType(LocalDateTime.class, new LocalDateTimeSerializer());
        };
    }

    private static Jackson2ObjectMapperBuilder customizeBuilder(Jackson2ObjectMapperBuilder builder) {
        builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer())
            // 将日期时间序列化为时间戳(以毫秒表示),而不是默认的日期时间字符串格式,如果已经设置了serializerByType则会失效
            .featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            // 允许将单个值解析为数组。这意味着如果 JSON 中的某个属性期望是数组类型,但实际上只有一个值,那么它也会被解析为数组。
            .featuresToEnable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
            // 解开包装在单个值数组中的值。这意味着如果 JSON 中的某个属性被包装在一个只有一个元素的数组中,那么它会被解包成单个值。
            .featuresToEnable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
        return builder;
    }

    public static final class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        public LocalDateTimeDeserializer() {}

        public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
            // 时间戳格式
            if (StringUtils.isNumeric(p.getValueAsString())) {
                long timestamp = Long.parseLong(p.getValueAsString());

                // 带毫秒
                if (p.getValueAsString().length() == 13) {
                    return Instant.ofEpochMilli(timestamp).atZone(JacksonConfiguration.zoneOffset).toLocalDateTime();
                }
                // 不带毫秒
                else {
                    return Instant.ofEpochSecond(timestamp).atZone(JacksonConfiguration.zoneOffset).toLocalDateTime();
                }
            } else {
                // 2023-09-08 16:12:25 或 2023-09-08T16:12:25 或 2023-09-08 16:12:25.456 格式
                String dateTimeString = p.getValueAsString();
                if (StringUtils.isNotEmpty(dateTimeString)) {
                    return LocalDateTime.parse(dateTimeString, optionalDateTimePattern);
                } else {
                    return null;
                }
            }
        }
    }

    public static final class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

        public LocalDateTimeSerializer() {}

        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException {
            gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        }
    }
}

实体类

当我在LocalDateTime类型的属性上使用@JsonForMat失效

public class TestDTO {

    @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime localDateTime;

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }

    @Override
    public String toString() {
        return "TestDTO{" + "localDateTime=" + localDateTime + '}';
    }
}

接口

调用接口的返回值是时间戳,而不是 yyyy/MM/dd HH:mm:ss

@PostMapping("/test7")
  public TestDTO test7() {
      TestDTO testDTO = new TestDTO();
      testDTO.setLocalDateTime(LocalDateTime.now());
      return testDTO;
  }

返回值:

{
    "localDateTime": 1706086696221
}

一种解决方法

改用 @JsonSerialize 注解

@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime localDateTime;

在外面定义一个LocalDateTimeSerializer,在serialize方法中定义要输出的格式

package com.xjhqre.config;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(value));
    }
}

你可能感兴趣的:(Java,spring,spring,boot,jackson,序列化)