解决SpringBoot接口返回Date类型及从数据库获取时间字段数据格式及时区问题

博客讲述了在API响应中遇到的日期时间格式转换问题,Spring默认使用Jackson进行JSON序列化,导致时间显示为标准时间。解决方案是在配置中设定`spring.jackson.time-zone: GMT+8`和`date-format`。同时讨论了数据库时区问题,特别是MySQL中时间存储与Web服务器时区不一致的情况,通过`serverTimezone`参数调整确保时间正确转换。
摘要由CSDN通过智能技术生成
问题描述

在API返回数据中含有Date类型的数据,这些数据在数据库中存储的格式为北京时间 yyyy-MM-dd HH:mm:ss格式,API的方法中获取到的时间也正常,但是在接口返回的数据中,时间变为了标准时间,格式也发生了变化,如:2021-07-28T06:30:10.378+00:00

原因分析

之所以会出现这样的情况,是因为Spring的消息转化机制引起的,对于返回值content-type类型为application/json格式的数据,默认使用jackson来进行json序列化,使用的消息转换器为org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
关于消息转换器的内容可以参考:SpringMVC源码剖析——消息转换器HttpMessageConverter

知道了这些以后我们还可以对返回数据进行其他的处理:
将jackson替换为fastjson:Springboot替换默认jackSon为fastJson过程
定制化返回数据:SpringBoot定制@ResponseBody注解返回的Json格式

解决办法

由于返回值content-type类型为application/json格式的数据,默认使用jackson来进行json序列化,所以只需要对jackson的属性进行设置即可,在配置文件中添加如下配置:

spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  • 默认情况下会将 时区设置为UTC ,Jackson反序列化时间类型的底层实际上调用的是Java的 SimpleDateFormat#parse() 方法,而JVM中的时区则会根据你的操作系统来获取,所以JVM认为你的时区应该是 GMT+8 时区,而要将 UTC 时区的时间转成 GMT+8 时区的时间,就会将你传进来的时间+8个小时。
  • 增加以上的配置的以后,则默认为接口的入参时间字段为(GMT+8)的时间;接口的出参为(GMT+8)的时间;【如果没有time-zone: GMT+8的配置,则会对接收到的时间按照UTC时间进行处理,如果系统所在时区为GMT+8,则会出现前端传过来的时间到后端以后被+8的情况;在输出数据的时候,则会认为要输出的日期字符串的时区是0时区,而现在的web服务器的时区是东8区,0时区比当前web服务器的东8区,慢8小时,所以转成UTC 的0时区后在进行输出。】

除了使用上述的配置也可以使用以下方式,直接配置到具体的字段上:

    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") // 设置出参的时区及格式
    // @DateTimeFormat(pattern="yyyy-MM-dd")// 设置入参的格式
    private Date createdDate;
连接数据库时的时区问题及serverTimeZone的作用

    在开发过程中,经常会发现,在将时间数据传入到数据库时,传入时东八区的时间,到数据库中以后就比传入的时间少了8个小时【例如:传入2021-09-27 10:30:30,数据库中写入的却为2021-09-27 02:30:30】,其实出现这种问题的原因是因为mysql数据库服务所在的时区与web服务所在的时区不一致导致的,【如:web服务器是在东八区,而mysql则是处于标准时间所在时区】;这种问题常见的解法如下:

# 加上serverTimezone=Asia/Shanghai
jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

但是这里就存在两个问题:

  • 时间的转换是在web服务器上进行的,还是在mysql上进行的?
  • serverTimezone参数的作用是什么?

这里直接上结论:
1、时间的转换是在web服务服务器上进行的,当从数据库中取值时,如果数据库服务器中存的时间为UTC时间,但是web服务器是在东八区,如果在web服务器中使用String类型来接收的话,会看到接收到的时间数据与数据库中的保持一致;如果用Date类型来接收的话,会转换为东八区的时间。
2、serverTimeZone的作用就是指定web服务器和mysql服务器的会话期间的mysql服务器时区,就是临时指定mysql服务器的时区。当不加这一个参数时,如果数据库服务器中存的时间为UTC时间,但是web服务器是在东八区,则web服务器检测到mysql服务器为UTC时间,则会对即将存入的时间-8然后存入到数据库,所以就会出现传入的数据与数据库中存入数据不一致的情况。

本节内容参考博文:
serverTimeZone的作用,mysql的时区,时区问题

Spring Boot 结合 MyBatisPlus 使用时,如果你想要控制数据返回时间格式(如`yyyy-MM-dd HH:mm:ss`而不是默认的`yyyy-MM-dd'T'HH:mm:ss.SSSZ`),你可以通过自定义全局结果映射器(Global Result Mapping)来实现。以下是一个简单的步骤: 1. 首先,创建一个全局结果映射器(GlobalResultMap)的实现类,比如`CustomJsonMapper.java`: ```java import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.Mybatis plus Plugin; import com.baomidou.mybatisplus.extension.plugins.interceptor.ResultInterceptor; import org.apache.ibatis.type.JdbcType; public class CustomJsonMapper extends BaseMapper implements Plugin { @Override public ResultInterceptor getInterceptors() { return new ResultInterceptor() { @Override public Object intercept(Object o, Method method, Object[] args, Map<String, Object> params) throws Throwable { if (method.getName().equals("selectOne") || method.getName().equals("selectList")) { // 这里假设查询结果为List<Object> List<?> list = (List<?>) o; for (Object item : list) { Date dateField = ((YourEntity) item).getFieldThatNeedsFormat(); // 替换为你的实体类名及需要格式化的字段 if (dateField != null) { params.put(dateField.toString(), dateField.toLocalDate()); // 将日期转换为LocalDate格式 } } } return o; } }; } @Override public String getInterceptorId() { return "customJsonMapper"; } @Override public boolean init(MetaObject metaObject) { return true; } @Override public void destroy() { } } ``` 这里假设`YourEntity`是你数据库表对应的实体类,并且有一个名为`fieldThatNeedsFormat`的时间字段。 2. 然后,在Spring Boot应用启动配置中启用这个插件,添加到MyBatis Plus的配置里: ```java import com.baomidou.mybatisplus.extension.MybatisPlusMapperFactoryBean; import com.baomidou.mybatisplus.extension.plugins.MybatisPlugin; ... @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusMapperFactoryBean mapperFactoryBean() { MybatisPlusMapperFactoryBean factoryBean = new MybatisPlusMapperFactoryBean(); factoryBean.setPlugins(new CustomJsonMapper()); return factoryBean; } } ``` 3. 别忘了将`CustomJsonMapper`注册到MyBatis Plus的插件列表中。 现在,当你从数据库获取到时间字段时,它将以`yyyy-MM-dd HH:mm:ss`的形式显示。如果有其他字段也需要特定格式化,可以相应地调整上述代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值