diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java index c62f0a030..b069c0a9c 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.framework.jackson.config; -import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; +import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; @@ -13,40 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.List; @AutoConfiguration @Slf4j public class YudaoJacksonAutoConfiguration { + /** + * 初始化全局 JsonUtils,直接使用主 ObjectMapper + */ @Bean @SuppressWarnings("InstantiationOfUtilityClass") - public JsonUtils jsonUtils(List objectMappers) { - // 1.1 创建 SimpleModule 对象 - SimpleModule simpleModule = new SimpleModule(); - simpleModule - // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型 - .addSerializer(Long.class, NumberSerializer.INSTANCE) - .addSerializer(Long.TYPE, NumberSerializer.INSTANCE) - .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE) - .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE) - .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE) - .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE) - // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 - .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) - .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); - // 1.2 注册到 objectMapper - objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); - - // 2. 设置 objectMapper 到 JsonUtils - JsonUtils.init(CollUtil.getFirst(objectMappers)); + public JsonUtils jsonUtils(ObjectMapper objectMapper) { + JsonUtils.init(objectMapper); log.info("[init][初始化 JsonUtils 成功]"); return new JsonUtils(); } + /** + * 从 Builder 源头定制(关键:使用 *ByType,避免 handledType 要求) + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() { + return builder -> builder + // Long -> String + .serializerByType(Long.class, NumberSerializer.INSTANCE) + .serializerByType(Long.TYPE, NumberSerializer.INSTANCE) + // LocalDate / LocalTime + .serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE) + .deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE) + .serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE) + .deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE) + // LocalDateTime < - > EpochMillis + .serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) + .deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); + } + + /** + * 以 Bean 形式暴露 Module(Boot 会自动注册到所有 ObjectMapper) + */ + @Bean + public Module timestampSupportModuleBean() { + SimpleModule m = new SimpleModule("TimestampSupportModule"); + // Long -> String,避免前端精度丢失 + m.addSerializer(Long.class, NumberSerializer.INSTANCE); + m.addSerializer(Long.TYPE, NumberSerializer.INSTANCE); + // LocalDate / LocalTime + m.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE); + m.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE); + m.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE); + m.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE); + // LocalDateTime < - > EpochMillis + m.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE); + m.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); + return m; + } + }