如何在 spring-mvc 中跳过杰克逊时区校正?
Posted
技术标签:
【中文标题】如何在 spring-mvc 中跳过杰克逊时区校正?【英文标题】:How to skip jackson timezone correction in spring-mvc? 【发布时间】:2018-10-07 07:49:19 【问题描述】:我想将jackson
配置为输出具有以下格式的任何日期/时间值:
spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss
我正在获取许多数据库行并将它们作为json
映射返回。
@RestController
public class MyService
@GetMapping
public List<Map<String, Object>> get(Param params)
return jdbcTemplate.queryForList(sql, params);
问题:数据库和 jvm 默认时区是Europe/Berlin
,因此是 UTC+2。因此,jackson 会先自动将任何数据库接收到的java.sql.Timestamp
转换为 UTC(减去 2 小时),然后通过 json 输出。
在mysql
数据库本身中,它是datetime
类型。
但我只想让杰克逊“按原样”输出时间戳,而不需要事先转换!是否可以跳过时区校正?
我只想忽略时区而不进行对话。剪掉就好了。
【问题讨论】:
您的数据库列数据类型是什么?你能避免Timestamp
类吗?它已经过时了。听起来您应该想要来自现代 Java 日期和时间 API java.time
的 LocalDateTime
数据类型。它没有时区,因此应该防止任何时区问题。 Instant
是另一种选择,具体取决于具体情况。
为了自动获得LocalDateTime
而不是java.sql.Timestamp
,我必须使用什么mysql
等效项?事实上,目前它是一个mysql datetime
数据类型。
这个问题可能有你要找的答案Jackson Serialization Ignore Timezone
这个问题我觉得是你需要的。***.com/questions/46151633/…
【参考方案1】:
方法一:设置默认时区
您可以使用ObjectMapper
使用的日期格式设置时区。它将用于Date
和子类:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(dateFormat);
在Spring应用中,要配置ObjectMapper
,可以如下操作:
@Bean
public ObjectMapper objectMapper()
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(dateFormat);
return mapper;
在 Spring Boot 中,您可以使用属性 spring.jackson.time-zone
来定义时区:
spring.jackson.time-zone: Europe/Berlin
有关常见应用程序属性的更多详细信息,请参阅documentation。
方法 #2:使用 Java 8 日期和时间 API
您可以考虑使用JSR-310 中的LocaDateTime
,而不是使用Timestamp
。它是在 Java 8 中引入的。“local” 日期和时间类(LocalDateTime
、LocalDate
和 LocalTime
)不依赖于任何一个地区或时区。来自LocalDateTime
文档:
此类不存储或表示时区。相反,它是对日期的描述,用于生日,结合挂钟上的当地时间。如果没有偏移或时区等附加信息,它不能代表时间线上的瞬间。
answer 将为您提供有关新日期和时间类的更多详细信息。
Jackson 有一个支持 JSR-310 类型的模块。将其添加到您的依赖项中:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9</version>
</dependency>
然后在您的ObjectMapper
实例中注册JavaTimeModule
模块:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
大多数 JSR-310 类型将使用标准的ISO-8601 字符串表示进行序列化。如果需要自定义格式,可以使用自己的序列化器和反序列化器实现。 详情请见documentation。
【讨论】:
好的,但我不能忽略时区吗?我正在连接到多个我事先不知道时区的数据库。据我了解,我必须在您的建议中将数据库时区设置为DateFormat
?
@membersound 如果你有不同的时区,而你故意忽略它们,你会不会得到不一致的结果?我在答案中添加了LocalDateTime
的替代方法。
很好的答案!如果时区信息是相关的,那么使用ZonedDateTime
而不是LocalDateTime
或至少OffsetDateTome
仅根据它们的偏移量来说明数据库之间的时间差异不是更好吗?
@CassioMazzochiMolin 在我的情况下,我必须使用旧数据库。我只想通过 json webservice 从数据库中“按原样”输出日期时间值。任何时区校正都无关紧要,我只想通过数据库中存在的 web 服务显示相同的值(并且由于 mysql datetime
类型独立于 timezone
,我还想防止 java 中的时区更正。跨度>
@membersound You could try to use a converter.【参考方案2】:
最后发现最简单的方法是将杰克逊ObjectMapper
(默认使用UTC
)时区设置为jvm默认值:
@Bean
public Jackson2ObjectMapperBuilderCustomizer init()
return new Jackson2ObjectMapperBuilderCustomizer()
@Override
public void customize(Jackson2ObjectMapperBuilder builder)
builder.timeZone(TimeZone.getDefault());
;
如果有人知道我如何通过使用spring.jackson.time-zone
application.property 来实现同样的目标,我将不胜感激。
【讨论】:
你试过在JsonFormat
中用timezone="Europe/Berlin"
注释java.util.Date
的字段吗?以上是关于如何在 spring-mvc 中跳过杰克逊时区校正?的主要内容,如果未能解决你的问题,请参考以下文章