自定义 LocalDateTimeDeserializer 全局json反序列化处理时区格式转换问题

自定义 LocalDateTimeDeserializer 全局json反序列化处理时区格式转换问题

点击 直接查看结论

背景 :

后端接收国际标准时间格式 yyyy-MM-ddTHH:mm:ss.SSSZ(eg: 2018-01-13T16:00:00.000Z) 的时间格式,要转换成东八区时间,也就是北京时间。我根据经验用如下这种常见的方式处理:

@Configuration
public class CusLocalDateTimeConfig {

    static final String PATTERN_UTC = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    static final String UTC_TAIL = "Z";
    
    @Bean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        builder.deserializerByType(LocalDateTime.class, CusLocalDateTimeDeserializer.CUS_INSTANCE);
        return builder.createXmlMapper(false).build();
    }

    /**
     * 继承默认的 LocalDateTimeDeserializer 重写反序列方法
     */
    public static class CusLocalDateTimeDeserializer extends LocalDateTimeDeserializer {

        public static final CusLocalDateTimeDeserializer CUS_INSTANCE = new CusLocalDateTimeDeserializer(DateTimeFormatter.ofPattern(PATTERN_UTC));

        public CusLocalDateTimeDeserializer(DateTimeFormatter formatter) {
            super(formatter);
        }

        @Override
        public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
            String timeStr = parser.getText();
            if (timeStr != null && !"".equals(timeStr)) {
                if (timeStr.endsWith(UTC_TAIL)) {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_UTC);
                    return LocalDateTime.parse(timeStr, formatter).plusHours(8);
                }
            }
            return super.deserialize(parser, context);
        }
    }
}

通过Jackson2ObjectMapperBuilder创建一个 ObjectMapper,指定对LocalDateTime的反序列化处理类为我自定义的处理类。

可是,执行了一下,压根没执行我自定义的这个反序列方法。网上搜了一下也没有找到相关问题。

所以决定看看源码找找问题:

因为我对springmvc大体流程还是比较了解,我后台controller是用的 @RequestBody 接收参数,所以参数处理类是RequestResponseBodyMethodProcessor 这个类的这个方法
在这里插入图片描述
跟着断点依次执行到这里
在这里插入图片描述
在这里插入图片描述
经过几次断点调试后发现,这个body就是完成参数处理后的对象,所以处理参数的就是messageConverters中的某一个类

再次断点发现是如下处理类

在这里插入图片描述

然后搜了一下,发现在springboot的自动配置类里面

在这里插入图片描述

通过ObjectMapper创建一个MappingJackson2HttpMessageConverter类型的bean

所以我之前的做法的完全正确的,但是通过ConditionalOnMissingBean我猜测,也许是项目里面已经定义了这样的Bean我全局搜了一下,果然在某个包中发现了这样一个东西。

ps:此功能主要是因为js的精度问题 序列化Long型为字符串
在这里插入图片描述

所以我就把上面的内容加到这个地方,问题就解决了。

当然中途还发现了很多框架中其他的有意思的操作,就不细述

总结 :

LocalDateTime 自定义时区转换的一种解决方式 : 全局反序列化处理 (此处以时间问题为例,当然也可以做其它任意操作)

1、对于参数是 @RequestBody 接收,也就是参数是json格式的场景:
 @PostMapping(value = "/post")
 public void save(@RequestBody Entity param)

第一种情况,项目中没使用自定义MappingJackson2HttpMessageConverter类型Bean的情况,可以直接创建一个ObjectMapper的Bean,指定builder中的反序列化类及对应类型


	@Bean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        builder.deserializerByType(LocalDateTime.class, CusLocalDateTimeDeserializer.CUS_INSTANCE);
        return builder.createXmlMapper(false).build();
    }

    /**
     * 自定义反序列化类
     * 继承默认的 LocalDateTimeDeserializer 重写反序列方法
     */
    public static class CusLocalDateTimeDeserializer extends LocalDateTimeDeserializer {

        public static final CusLocalDateTimeDeserializer CUS_INSTANCE = new CusLocalDateTimeDeserializer(DateTimeFormatter.ofPattern(PATTERN_UTC));

        public CusLocalDateTimeDeserializer(DateTimeFormatter formatter) {
            super(formatter);
        }

        @Override
        public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
            String timeStr = parser.getText();
            if (timeStr != null && !"".equals(timeStr)) {
                if (timeStr.endsWith(UTC_TAIL)) {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_UTC);
                    return LocalDateTime.parse(timeStr, formatter).plusHours(8);
                }
            }
            return super.deserialize(parser, context);
        }
    }


第二种情况,自定义MappingJackson2HttpMessageConverter类型的bean,(如果存在多个Bean,先加载的先执行,后加载的就不会再执行。可以通过@Order控制。但是注意千万别随意这样做) 在其他人也定义了Bean的时候,最好还是把功能放在同一个mappingJackson2HttpMessageConverter。以免导致其他功能失效

	//在此之前应该先检查项目中有没有其他人创建MappingJackson2HttpMessageConverter类型的Bean
	@Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(LocalDateTime.class, CusLocalDateTimeDeserializer.CUS_INSTANCE);
        objectMapper.registerModule(javaTimeModule);
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        return mappingJackson2HttpMessageConverter;
    }
2、对于参数是普通实体类接收 ,非json格式的场景:
 @GetMapping(value = "/get")
 public void save(Entity param)

可以实现 GenericConverter 或者 ConditionalGenericConverter

	/**
     * 自定义字符串到LocalDateTime的普通参数转换
     *
     **/
    @Component
    public class StringToLocalDateTimeConverter implements GenericConverter {

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            //将字符串转化为LocalDateTime
            return Collections.singleton(new ConvertiblePair(String.class, LocalDateTime.class));
        }
		//具体转换方法
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            if (((String) source).endsWith("Z")) {
                return stringToLocalDateTimeUtc((String) source);
            }
            return stringToLocalDateTimeGeneral((String) source);
        }
    }

ConditionalGenericConverter ,他多提供了一个是否采用此方法的判断

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在C#中,Newtonsoft.Json提供了多种处理日期格式的方式。一种常见的方式是在属性上使用`[JsonConverter]`特性来指定日期格式的转换器。你可以创建一个自定义的日期转换器,继承自`JsonConverter`类,并实现其中的`ReadJson`和`WriteJson`方法来自定义日期的序列化和反序列化过程。在`ReadJson`方法中,你可以根据不同的日期格式进行解析,然后将其转换为C#的`DateTime`类型。在`WriteJson`方法中,你可以将`DateTime`类型转换为指定的日期格式字符串。这样,你就可以根据不同的需求来处理不同的日期格式了。 另外,Newtonsoft.Json还提供了一个全局设置,可以通过`JsonConvert.DefaultSettings`属性来配置默认的序列化和反序列化设置。你可以在其中设置`DateFormatHandling`属性来指定日期的处理方式,包括日期格式化字符串、日期格式化的方式以及日期的时区等。通过这种方式,你可以统一处理整个应用程序中的日期格式。 总结来说,C#中的Newtonsoft.Json提供了灵活的方式来处理多种日期格式。你可以通过自定义日期转换器或者全局设置来满足不同的需求。这样,你就能够轻松地处理不同格式的日期数据了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Newtonsoft.Json 反序列化时对json注释的处理](https://blog.csdn.net/u010476739/article/details/124941822)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [使用Newtonsoft.Json快速实现序列化与反序列化](https://blog.csdn.net/weixin_43675051/article/details/130310993)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值