• 关于LocalDateTime的全局返回时间带“T“的时间格式处理


    关于LocalDateTime的全局返回带"T"的时间格式处理

    关于背景的大概描述,如下。
    时间类型LocalDateTime相较于于Date的确有自己独特的优势,因此在之后的版本迭代上,将部分隔离开的模块使用了新型的LocalDateTime替代了Date,因已经使用了全局时间转换,但是测试的时候发现返回的时间格式很奇怪 2022-01-01T00:00:00.000,全局时间序列化、反序列化并没有起作用,寻找相关资料和DEGBU之后将相关资料整理如下。
    目前常用的时间类型格式如下:

    时间类型

    时间默认格式

    Date

    Tue Feb 01 00:00:00 CST 2022

    Timestamp

    2022-01-01 00:00:00.0

    LocalDateTime

    2022-01-01T00:00:00.000

    1.关于jackson的全局返回带T的处理方式

    对于Date和Timestamp在引入LocalDateTime之前是经过spring.jackson.date-format进行全局数据绑定格式化时间类型。

    spring:
    	jackson:
    		date-format: 格式化类
    
    • 1
    • 2
    • 3

    在格式化类中添加对LocalDateTime的格式化语句发现无效果。经过搜索资料后发现在使用jackson在对localDateTime类型的序列化和反序列化方法另有其他方法。(这里不输出关于源码内的信息。可自行查看。)

    // 涉及源码类 其余的可自行debug追踪
    Jackson2ObjectMapperBuilder
    Jackson2ObjectMapperBuilderCustomizer // 最终做处理的服务类
    JacksonAutoConfiguration
    
    
    @Configuration
    public class LocalDateTimeSerializerConfig {
    	// jackson注册的时候会将序列化和反序列化的方法提前注册进,做数据转换会自行根据具体的实现去调用。
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
            return builder -> {
                builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer());
            };
        }
    
        /**
         * 反序列化
         */
        public static class LocalDateTimeDeserializer extends JsonDeserializer {
            @Override
            public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
                    throws IOException {
                long timestamp = p.getValueAsLong();
                if (timestamp > 0) {
                    return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
                } else {
                    return null;
                }
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.关于fastjson的全局返回带T的处理方式

    使用fastjson进行时间格式化处理,自己写的类去实现 WebMvcConfigurer配置类,重写父类方法configureMessageConverters,在进行全局时间返回格式绑定后,之前使用的格式化时间类是fastjson自身提供的SimpleDateFormatSerializer方法,发现在进行对LocalDateTime添加后进行时间转化返回后存在异常,异常信息提示LocalDateTime不能强转为Date,进行多次DEBUG跟踪后定位到了SimpleDateFormatSerializer方法内部,会将拿到的value直接进行Date的强转,SimpleDateFormatSerializer源码如下

    public class SimpleDateFormatSerializer implements ObjectSerializer {
    
        private final String pattern;
    
        public SimpleDateFormatSerializer(String pattern){
            this.pattern = pattern;
        }
    
        public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        	if (object == null) {
        		serializer.out.writeNull();
        		return;
        	}
        	// 对LocalDateTime 进行强制转换,此处会报错。因此,主要的重点改造就是此处。
            Date date = (Date) object;
            SimpleDateFormat format = new SimpleDateFormat(pattern, serializer.locale);
            format.setTimeZone(serializer.timeZone);
            String text = format.format(date);
            serializer.write(text);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    既然已经发现问题的关键点那对关键点进行处理即可,目前有两个方法:

    1. 写好SimpleDateFormatSerializer的继承类
    2. 实现ObjectSerializer的write方法进行处理。

    我选用的是第一种方式对SimpleDateFormatSerializer集成后重写write方法,因为之前的时间格式已经使用的SimpleDateFormatSerializer进行处理,为了稳定进行最小程度的调整。结果如下

    public class OwnSimpleDateFormatSerializer extends SimpleDateFormatSerializer {
    
        private final String pattern;
    
        public OwnSimpleDateFormatSerializer (String pattern) {
            super(pattern);
            this.pattern = pattern;
        }
    
    
        @Override
        public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
            if (object == null) {
                serializer.out.writeNull();
            } else {
                Date date = null;
                // 改造内容 增加类型判断进行处理
                if (object instanceof LocalDateTime) {
                    LocalDateTime localDateTime = (LocalDateTime) object;
                    date = Date.from(localDateTime.atZone( ZoneId.systemDefault()).toInstant());
                } else {
                    date = (Date)object;
                }
                SimpleDateFormat format = new SimpleDateFormat(this.pattern, Locale.SIMPLIFIED_CHINESE);
                TimeZone timeZone = new ZoneInfo();
                timeZone.setRawOffset(28800000);
                timeZone.setID("Asia/Shanghai");
                format.setTimeZone(timeZone);
                String text = format.format(date);
                serializer.write(text);
            }
        }
    }
    
    
    // 涉及类
    WebMvcConfigurer
    SimpleDateFormatSerializer // 之前使用的时间格式化类
    ObjectSerializer // 最终执行时间格式化处理的服务类
    FastJsonConfig // 配置类
    SerializeConfig // 序列化配置信息
    
    
    @Component
    public class DefaultMvcFilter implements WebMvcConfigurer {
    
        @Override
        public void configureMessageConverters(List> converters) {
    		 // ...
    		 // 重点在此 对FastJsonConfig进行配置
    		FastJsonConfig fastJsonConfig = new FastJsonConfig();
    		 // 修改全局json配置
    		SerializeConfig serializeConfig = SerializeConfig.globalInstance;
    		 // 格式化时间
    		serializeConfig.put(Date.class, new OwnSimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
    		serializeConfig.put(java.sql.Date.class, new OwnSimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
    		serializeConfig.put(java.sql.Timestamp.class, new OwnSimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
    		serializeConfig.put(java.sql.Time.class, new OwnSimpleDateFormatSerializer("HH:mm:ss"));
    		// 对LocalDateTime进行时间格式化 注意序列化的实现类 是需要自己写的,并不是使用fastjson自带的SimpleDateFormatSerializer
    		serializeConfig.put(LocalDateTime.class, new OwnSimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
    		fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
    		fastJsonConfig.setSerializeConfig(serializeConfig);
    		fastJsonConfig.setSerializerFeatures(
    				SerializerFeature.WriteDateUseDateFormat,
    				SerializerFeature.IgnoreErrorGetter,
    				SerializerFeature.WriteNullNumberAsZero,
    				SerializerFeature.WriteNullBooleanAsFalse,
    				SerializerFeature.DisableCircularReferenceDetect
    		);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    以上对于jackson和fastjson改造完成后进行测试,发现时间格式全部展示正确,以此来记录问题发生和处理方式。主要还是根据源码跟踪来确定问题,问题确定后的处理就会有很多方式了,选择最适用的处理方式即可。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    内卷了,阿里 Java 八股文面试题“惨遭”泄露,导致 132 人面进大厂
    电脑msvcp140丢失报错解决方法,msvcp140.dll重新安装的解决方法
    AOP详解
    2022.9.29
    [晕事]今天做了件晕事22;寻找99-sysctl.conf; systemd
    模型降阶方法之 POD
    SpringDataRedis快速入门(一)
    Java利用工具类提升写报表效率
    18.webpack4之HMR
    葡萄糖-聚乙二醇-人血清白蛋白,HAS-PEG-Glucose,人血清白蛋白-PEG-葡萄糖
  • 原文地址:https://blog.csdn.net/m0_61083409/article/details/126080956