From ea3d5ed121d20993c366c1302c73e618d1e01b38 Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 26 Aug 2026 19:08:01 +0800 Subject: [PATCH] =?UTF-8?q?json=E5=BA=8F=E5=88=97=E5=8C=96=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunhai/userhome/config/JacksonConfig.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/main/java/com/yunhai/userhome/config/JacksonConfig.java diff --git a/src/main/java/com/yunhai/userhome/config/JacksonConfig.java b/src/main/java/com/yunhai/userhome/config/JacksonConfig.java new file mode 100644 index 0000000..cae79ec --- /dev/null +++ b/src/main/java/com/yunhai/userhome/config/JacksonConfig.java @@ -0,0 +1,75 @@ +package com.yunhai.userhome.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Arrays; +import java.util.List; + +/** + * Jackson 全局配置:统一 java.time.LocalDateTime 的反序列化格式。 + * + *

背景:UserBase 跨仓接口(如 /oapi/app/list)返回的时间是 "yyyy-MM-dd HH:mm:ss"(空格分隔), + * 而 Jackson 默认的 LocalDateTimeDeserializer 只接受 ISO 格式("yyyy-MM-dd'T'HH:mm:ss"), + * 导致 OpenAPI 客户端反序列化 BoaApp.createTime 时抛 DateTimeParseException, + * 消息中心(getMessageByUserId)等接口因此报"内部服务错误"。 + * + *

yh-openapi 的 OpenApiAutoConfiguration.openApiObjectMapper() 带 @ConditionalOnMissingBean, + * 本工程定义该 ObjectMapper bean 后即被 OpenAPI 客户端(OpenApiHttpClient / AbstractOpenApiClient)采用; + * 同时它也是 Spring MVC 使用的全局 mapper,因此同样保留 spring.jackson.* 配置(GMT+8 时区、 + * java.util.Date 的 yyyy-MM-dd HH:mm:ss 格式)。 + */ +@Configuration +public class JacksonConfig { + + /** 兼容的 LocalDateTime 字符串格式,按优先级依次尝试:先 UserBase 的空格格式,再 ISO 格式。 */ + private static final List LOCAL_DATE_TIME_FORMATTERS = Arrays.asList( + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"), + DateTimeFormatter.ISO_LOCAL_DATE_TIME); + + @Bean + @Primary + public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { + SimpleModule module = new SimpleModule(); + module.addDeserializer(LocalDateTime.class, new FlexibleLocalDateTimeDeserializer()); + return builder.modulesToInstall(module).build(); + } + + /** + * 兼容 "yyyy-MM-dd HH:mm:ss" 与 ISO 格式的 LocalDateTime 反序列化器; + * 字符串以外的输入(如数字时间戳)沿用 Jackson 默认处理。 + */ + private static class FlexibleLocalDateTimeDeserializer extends LocalDateTimeDeserializer { + + private FlexibleLocalDateTimeDeserializer() { + super(DateTimeFormatter.ISO_LOCAL_DATE_TIME); + } + + @Override + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.hasToken(JsonToken.VALUE_STRING)) { + String text = p.getText(); + for (DateTimeFormatter formatter : LOCAL_DATE_TIME_FORMATTERS) { + try { + return LocalDateTime.parse(text, formatter); + } catch (DateTimeParseException ignored) { + // 继续尝试下一种格式 + } + } + } + return super.deserialize(p, ctxt); + } + } +}