1. 概述
Spring Data MongoDB 模块极大地提升了在 Spring 项目中与 MongoDB 数据库交互的可读性和易用性。
本篇文章将重点介绍如何在使用 Spring Data MongoDB 读写 MongoDB 数据库时,正确处理 Java 中的 ZonedDateTime
对象。
2. 环境准备
要使用 Spring Data MongoDB 模块,首先需要添加以下 Maven 依赖:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.4.7</version>
</dependency>
最新版本可以在 Maven Central 查找。
接下来定义一个简单的模型类 Action
,其中包含一个 ZonedDateTime
类型的字段:
@Document
public class Action {
@Id
private String id;
private String description;
private ZonedDateTime time;
// 构造函数、getter 和 setter 省略
}
为了与 MongoDB 交互,我们还需要创建一个继承自 MongoRepository
的接口:
public interface ActionRepository extends MongoRepository<Action, String> { }
然后我们编写一个测试方法,插入一个 Action
对象并验证其时间字段是否被正确存储。由于 MongoDB 的 Date
类型精度为毫秒,因此我们在断言中移除了纳秒部分:
@Test
public void givenSavedAction_TimeIsRetrievedCorrectly() {
String id = "testId";
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
actionRepository.save(new Action(id, "click-action", now));
Action savedAction = actionRepository.findById(id).get();
Assert.assertEquals(now.withNano(0), savedAction.getTime().withNano(0));
}
如果直接运行测试,会抛出如下异常:
org.bson.codecs.configuration.CodecConfigurationException:
Can't find a codec for class java.time.ZonedDateTime
✅ 这是因为 Spring Data MongoDB 默认没有为 ZonedDateTime
提供编解码器。 接下来我们将介绍如何配置自定义转换器来解决这个问题。
3. 自定义 MongoDB 转换器
我们可以通过定义两个转换器(读取转换器和写入转换器)来全局处理 ZonedDateTime
类型的字段。
3.1 读取转换器:Date → ZonedDateTime
public class ZonedDateTimeReadConverter implements Converter<Date, ZonedDateTime> {
@Override
public ZonedDateTime convert(Date date) {
return date.toInstant().atZone(ZoneOffset.UTC);
}
}
由于 MongoDB 的 Date
类型不包含时区信息,这里我们统一使用 UTC 时区。
3.2 写入转换器:ZonedDateTime → Date
public class ZonedDateTimeWriteConverter implements Converter<ZonedDateTime, Date> {
@Override
public Date convert(ZonedDateTime zonedDateTime) {
return Date.from(zonedDateTime.toInstant());
}
}
将这两个转换器注册到 MongoCustomConversions
中之后,测试即可通过。
此时存储的对象打印出来大致如下:
Action{id='testId', description='click', time=2018-11-08T08:03:11.257Z}
⚠️ 注意:如果需要保留原始时区信息,可以考虑将时区单独存储在一个额外字段中。
如需了解更多关于 MongoDB 转换器的注册方式,可参考 Spring Data MongoDB 转换器配置教程。
4. 小结
本文简要介绍了如何通过自定义 MongoDB 转换器来支持 Java 中的 ZonedDateTime
类型,解决 Spring Data MongoDB 默认不支持该类型的问题。
所有示例代码均可在 GitHub 上获取:GitHub 项目地址。