Spring Boot升级到2.x,Jackson对Date时间类型序列化的变化差点让项目暴雷【享学Spring Boot】(上)

简介: Spring Boot升级到2.x,Jackson对Date时间类型序列化的变化差点让项目暴雷【享学Spring Boot】(上)

前言


在阅读本文之前,建议你已经掌握了Jackson的知识以及它的Spring、Spring Boot下的集成和运用。


说明:若不熟悉Jackson,请务必参阅我的专栏[享学Jackson](单击这里电梯直达),该专栏有可能是全网最好、最全的完整教程。


本文讲述的是本人在生产上的一个真实案例,分享给大家,避免你采坑。它的大背景是项目需要从Spring Boot1.x升级到2.x版本,升上去之后由于Jackson对时间类型序列化的变化,使得多个项目险些暴雷,幸好本人对Jackson很了解所以迅速定位并且解决问题,及时止损。


说明:因为我写这个是个脚手架,供给多个团队使用。在Jackson这点上没有考虑好向下兼容性导致多个项目差点暴雷,幸好及时止损。


正文


大家都知道,Spring Boot2.x对1.x版本是不向下兼容的,如果你曾经做过升级、或者Spring MVC -> Spring Boot2.x的迁移,相信你或多或少遇到过些麻烦。确实,Spring Boot的API设计者、代码编写者的“实力”是不如Spring Framework的,所以即使是同体系的1.x -> 2.x都会遇到不少问题(这里不包括编译问题)。


本文的关注点是Spring Boot不同大版本下Jackson对日期/时间类型的序列化问题。据我调查和了解,该问题也是很多同学的痛点,所以相信本文能帮助到你避免采坑。

Spring Boot 1.x和2.x差异


Spring Boot因它经常升级而不具有向下兼容性而向来“臭名昭著”,其中大版本号升级1.x升级到2.x尤为凸显,本文将采用这两个不同大版本,对其对日期/时间类型序列化表现作出对比。使用的Spring Boot版本号公式如下:


  • 1.x版本号是:1.5.22.RELEASE(1.x版本的最后一个版本,并且在2019.8.1宣布停止维护)
  • 2.x版本号是:2.0.0.RELEASE(2018.3.1发布)


说明:本文使用2.0.0.RELEASE版本,而非使用和享学Jackson 专栏一致的版本号,是想强调说明:这个差异是发生在1.x和2.x交替之时,而非2.x之后的变化。


Jar包差异


不同的Spring Boot导入的Jar版本是不一样的,这个差异在大版本号之间也不容忽略。


1.x版本:

image.png


2.x版本:

image.png



小总结


从截图方面可看出,Jar包导入方面差异还是挺大的:


  • 1.x只自动给你导入了三大核心包,三个常用三方包一个都木有帮你导入
  • 1.x版本最低基于JDK6构建的,所以默认其它三方包就没导入。但若你是基于JDK8构建的,强烈建议你手动导入常用三方包
  • 2.x通过web带入了spring-boot-starter-json这个启动器,该启动器管理着“所有”有用的Jackson相关Jar包,不仅仅是核心包
  • 2.x版本对JDK的最低要求是JDK8,所以默认就给你带上这三个常用模块是完全合理的
  • 1.x使用的Jackson版本号是:2.8.11.3;2.x使用的Jackson版本号是2.9.4;版本差异上并不大,可忽略


ObjectMapper表现


我们知道Spring Boot默认情况下是向容器内放置了一个ObjectMapper实例的,因此我们可以直接使用,下面案例就是这样做的。


公用代码:


@Autowired
ObjectMapper objectMapper;
@Test
public void contextLoads() throws JsonProcessingException {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("date", new Date());
    map.put("timestamp", new Timestamp(System.currentTimeMillis()));
    map.put("localDateTime", LocalDateTime.now());
    map.put("localDate", LocalDate.now());
    map.put("localTime", LocalTime.now());
    map.put("instant", Instant.now());
    System.out.println(objectMapper.writeValueAsString(map));
}



在不同的Spring Boot版本上的输出,表现如下:

1.x版本:


{
    "date":1580897613003,
    "timestamp":1580897613003,
    "localDateTime":{
        "dayOfMonth":5,
        "dayOfWeek":"WEDNESDAY",
        "month":"FEBRUARY",
        "year":2020,
        "hour":18,
        "minute":13,
        "nano":9000000,
        "second":33,
        "dayOfYear":36,
        "monthValue":2,
        "chronology":{
            "id":"ISO",
            "calendarType":"iso8601"
        }
    },
    "localDate":{
        "year":2020,
        "month":"FEBRUARY",
        "dayOfMonth":5,
        "dayOfWeek":"WEDNESDAY",
        "era":"CE",
        "chronology":{
            "id":"ISO",
            "calendarType":"iso8601"
        },
        "dayOfYear":36,
        "leapYear":true,
        "monthValue":2
    },
    "localTime":{
        "hour":18,
        "minute":13,
        "second":33,
        "nano":9000000
    },
    "instant":{
        "epochSecond":1580897613,
        "nano":9000000
    }
}


2.x版本:


{
    "date":"2020-02-05T10:15:36.520+0000",
    "timestamp":"2020-02-05T10:15:36.520+0000",
    "localDateTime":"2020-02-05T18:15:36.527",
    "localDate":"2020-02-05",
    "localTime":"18:15:36.527",
    "instant":"2020-02-05T10:15:36.527Z"
}


小总结

1.x的执行效果同:


@Test
public void fun1() throws JsonProcessingException {
    ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("date", new Date());
    map.put("timestamp", new Timestamp(System.currentTimeMillis()));
    map.put("localDateTime", LocalDateTime.now());
    map.put("localDate", LocalDate.now());
    map.put("localTime", LocalTime.now());
    map.put("instant", Instant.now());
    System.out.println(mapper.writeValueAsString(map));
}


2.x的执行效果同:

@Test
public void fun1() throws JsonProcessingException {
    ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  ... // 省略map(同上)
    System.out.println(mapper.writeValueAsString(map));
}


可以看到,他们的差异仅在一个特征值SerializationFeature.WRITE_DATES_AS_TIMESTAMPS是否开启。然后Spring Boot不同版本上对此值有差异:


  • 1.x下此特征开启(这是Jackson的默认行为,是开启的)
  • 2.x下此特征关闭



相关文章
|
6天前
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
如何在SpringBoot项目中使用过滤器和拦截器
|
9天前
|
XML 前端开发 Java
还不会SpringBoot项目模块分层?来这手把手教你
本文详细介绍了如何为SpringBoot项目创建模块并进行合理的分层设计。通过逐步演示,从创建项目到构建各功能模块,再到具体代码实现,手把手教你实现整洁的代码分层。主要内容包括:创建依赖层、主启动层、模块层及其子模块(如共通层、控制器层、数据持久层等),并通过实例演示了从前端请求到后台服务调用的实际流程。适合SpringBoot初学者及有一定经验但需优化项目结构的开发者参考。
35 2
还不会SpringBoot项目模块分层?来这手把手教你
|
9天前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
23 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
18天前
|
JavaScript 前端开发 Java
SpringBoot + Vue 前端后分离项目精进版本
这篇文章详细介绍了一个基于SpringBoot + Vue的前后端分离项目的搭建过程,包括前端Vue项目的初始化、依赖安装、页面创建和路由配置,以及后端SpringBoot项目的依赖添加、配置文件修改、代码实现和跨域问题的解决,最后展示了项目运行效果。
SpringBoot + Vue 前端后分离项目精进版本
|
19天前
|
Java
SpringBoot项目配置热部署启动 及 热部署失效的问题解决
这篇文章介绍了如何在SpringBoot项目中配置热部署启动,包括在pom文件中添加热部署依赖、在IDEA中进行设置、修改配置文件以及IDEA启动设置,以解决热部署失效的问题。
SpringBoot项目配置热部署启动 及 热部署失效的问题解决
|
9天前
|
小程序 前端开发 JavaScript
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
【避坑宝】是一款企业黑红名单吐槽小程序,旨在帮助打工人群体辨别企业优劣。该平台采用SpringBoot+MybatisPlus+uniapp+uview2等技术栈构建,具备丰富的注释与简洁的代码结构,非常适合实战练习与学习。通过小程序搜索“避坑宝”即可体验。
24 0
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
|
9天前
|
JavaScript 前端开发 小程序
【项目实战】SpringBoot+vue+iview打造一个极简个人博客系统
这是一个基于 SpringBoot+MybatisPlus+Vue+Iview 技术栈构建的个人极简博客系统,适合初学者实战练习。项目包含文章分类、撰写文章、标签管理和用户管理等功能,代码简洁并配有详细注释,易于上手。此外,该项目也可作为毕业设计的基础进行二次开发。
36 0
【项目实战】SpringBoot+vue+iview打造一个极简个人博客系统
|
16天前
|
安全 Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+jsp实现的健身房管理系统(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和JSP技术实现的健身房管理系统。随着健康生活观念的普及,健身房成为日常锻炼的重要场所,高效管理会员信息、课程安排等变得尤为重要。该系统旨在通过简洁的操作界面帮助管理者轻松处理日常运营挑战。技术栈包括:JDK 1.8、Maven 3.6、MySQL 8.0、JSP、Shiro、Spring Boot 2.0等。系统功能覆盖登录、会员管理(如会员列表、充值管理)、教练管理、课程管理、器材管理、物品遗失管理、商品管理及信息统计等多方面。
|
15天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的前后端分离的考试管理系统(含教程&源码&数据库数据)
在数字化时代背景下,本文详细介绍了如何使用Spring Boot框架结合Vue.js技术栈,实现一个前后端分离的考试管理系统。该系统旨在提升考试管理效率,优化用户体验,确保数据安全及可维护性。技术选型包括:Spring Boot 2.0、Vue.js 2.0、Node.js 12.14.0、MySQL 8.0、Element-UI等。系统功能涵盖登录注册、学员考试(包括查看试卷、答题、成绩查询等)、管理员功能(题库管理、试题管理、试卷管理、系统设置等)。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的前后端分离的考试管理系统(含教程&源码&数据库数据)
|
19天前
|
JavaScript Java Maven
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和Vue.js实现的在线求职平台。该平台采用了前后端分离的架构,使用Spring Boot作为后端服务
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
下一篇
DDNS