You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为不同控制器的共享对象配置ZonedDateTime的序列化与反序列化?

不同Controller使用不同ZonedDateTime反序列化规则的解决方案

针对你遇到的问题,这里提供几个可行的实现方案,按需选择:

方案1:按请求路径配置专属消息转换器

通过为不同路径的请求配置独立的MappingJackson2HttpMessageConverter,每个转换器绑定对应格式的ObjectMapper,Spring会根据请求路径自动匹配对应的转换器。

实现步骤:

  1. 创建两个自定义的ObjectMapper实例,分别配置对应的日期反序列化规则:
private ObjectMapper createWebObjectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    JavaTimeModule timeModule = new JavaTimeModule();
    // Web端日期格式:yyyy-MM-dd HH:mm:ssX
    timeModule.addDeserializer(ZonedDateTime.class, 
        new ZonedDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX")));
    mapper.registerModule(timeModule);
    return mapper;
}

private ObjectMapper createMobileObjectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    JavaTimeModule timeModule = new JavaTimeModule();
    // Mobile端日期格式:yyyy-MM-dd'T'HH:mm:ssX
    timeModule.addDeserializer(ZonedDateTime.class, 
        new ZonedDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX")));
    mapper.registerModule(timeModule);
    return mapper;
}
  1. 在Spring配置类中注册这两个转换器,并指定路径匹配规则:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // Web端转换器,匹配/web/**路径
        MappingJackson2HttpMessageConverter webConverter = 
            new MappingJackson2HttpMessageConverter(createWebObjectMapper());
        webConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));
        webConverter.setMatcher(new PathPatternsRequestCondition("/web/**"));

        // Mobile端转换器,匹配/mobile/**路径
        MappingJackson2HttpMessageConverter mobileConverter = 
            new MappingJackson2HttpMessageConverter(createMobileObjectMapper());
        mobileConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));
        mobileConverter.setMatcher(new PathPatternsRequestCondition("/mobile/**"));

        // 将自定义转换器放在列表最前面,优先使用
        converters.add(0, webConverter);
        converters.add(1, mobileConverter);
    }
}

优点:逻辑解耦,不同路径的序列化规则完全独立,适合复杂的全局配置场景。
缺点:配置相对繁琐,需要了解Spring消息转换器的工作机制。


方案2:自定义上下文感知的反序列化器

编写一个自定义的ZonedDateTime反序列化器,根据当前请求的路径动态选择日期格式,无需配置多个ObjectMapper。

实现步骤:

  1. 实现上下文感知的反序列化器:
public class ContextAwareZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {

    private static final DateTimeFormatter WEB_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX");
    private static final DateTimeFormatter MOBILE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX");

    public ContextAwareZonedDateTimeDeserializer() {
        super(ZonedDateTime.class);
    }

    @Override
    public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        // 获取当前请求对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestPath = request.getRequestURI();
        String dateStr = p.getText();

        if (requestPath.startsWith("/web/")) {
            return ZonedDateTime.parse(dateStr, WEB_FORMAT);
        } else if (requestPath.startsWith("/mobile/")) {
            return ZonedDateTime.parse(dateStr, MOBILE_FORMAT);
        }
        // 路径不匹配时抛出异常,或设置默认格式
        throw new IllegalArgumentException("Unsupported request path for date parsing: " + requestPath);
    }
}
  1. 在TestObject的testTime字段上指定使用该反序列化器:
public class TestObject {
    @JsonDeserialize(using = ContextAwareZonedDateTimeDeserializer.class)
    private ZonedDateTime testTime;

    // getter、setter方法
}

优点:实现简单,无需修改Spring全局配置,代码侵入性低。
缺点:依赖RequestContextHolder获取请求上下文,耦合Web环境,单元测试时需要模拟请求对象。


方案3:使用不同的DTO类

创建两个继承自TestObject的DTO子类,分别配置不同的日期格式,两个Controller各自使用对应的DTO作为请求体。

实现步骤:

  1. 定义基础类和两个子类:
// 基础类,包含除testTime外的公共字段
public class TestObject {
    // 其他公共字段及getter、setter
}

// Web端专用DTO
public class TestObjectWeb extends TestObject {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ssX")
    private ZonedDateTime testTime;

    // getter、setter方法
}

// Mobile端专用DTO
public class TestObjectMobile extends TestObject {
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssX")
    private ZonedDateTime testTime;

    // getter、setter方法
}
  1. 两个Controller分别使用对应的DTO:
@RestController
@RequestMapping("/web")
public class ControllerWeb {
    @PostMapping("/test")
    public void handleWebRequest(@RequestBody TestObjectWeb testObject) {
        // 业务逻辑
    }
}

@RestController
@RequestMapping("/mobile")
public class ControllerMobile {
    @PostMapping("/test")
    public void handleMobileRequest(@RequestBody TestObjectMobile testObject) {
        // 业务逻辑
    }
}

优点:实现最简单,无需复杂配置,逻辑清晰。
缺点:如果TestObject字段较多,会产生代码冗余,需要维护多个DTO类。


内容的提问来源于stack exchange,提问作者Salvatore Grazioso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 11:52:40