Java 仅为一个字段写入Mongo转换器
我有一个简单的POJO,其中有一个长字段,实际上是一个时间戳 此字段必须位于由ISODate表示的mongo数据库中 我可以为整个Pojo编写一个转换器,但由于25个字段中只有一个字段没有多大意义,而且当一个字段发生更改或添加了一个字段时,这是另一个错误点 是否有一种方法可以调用默认转换器服务,并在默认转换服务之后更改另外两个,这将对性能产生很大影响。 或者是否有要覆盖的默认转换器接口 这里的最佳做法是什么 也许有一个注释我可以应用到这个领域 是的,我也可以写一个长脚转换器,但这会影响所有的POJO,而不仅仅是这一个 下面是示例POJO:Java 仅为一个字段写入Mongo转换器,java,mongodb,spring-data,Java,Mongodb,Spring Data,我有一个简单的POJO,其中有一个长字段,实际上是一个时间戳 此字段必须位于由ISODate表示的mongo数据库中 我可以为整个Pojo编写一个转换器,但由于25个字段中只有一个字段没有多大意义,而且当一个字段发生更改或添加了一个字段时,这是另一个错误点 是否有一种方法可以调用默认转换器服务,并在默认转换服务之后更改另外两个,这将对性能产生很大影响。 或者是否有要覆盖的默认转换器接口 这里的最佳做法是什么 也许有一个注释我可以应用到这个领域 是的,我也可以写一个长脚转换器,但这会影响所有的PO
public class Person {
private long someTimestamp;
//getters and setters
}
如果没有转换器,这看起来是这样的:
{
"_id" : ObjectId("52ae8eede4b0249cde22059e"),
"someTimestamp" : NumberLong(1392714950940)
}
结果应该是这样的:
{
"_id" : ObjectId("52ae8eede4b0249cde22059e"),
"someTimestamp" : ISODate("2013-12-23T23:00:00.000Z")
}
如果exmaple的嵌套文档中有这样一个TIMESTAMP值,则描述的问题会变得更加复杂:
{
"_id" : ObjectId("52ae8eede4b0249cde22059e"),
"items" : [
"someTimestamp" : NumberLong(1392714950940)
]
}
POJO:
公共类人物{
私人收藏物品;
//接球手和接球手
}
也许我应该提到,我正在使用Spring来实现这一点。()不能仅为一个类定义
转换器。但在morphia将数据映射回类之前,您可以使用@PreLoad
对数据进行处理:
@PreLoad
void convertDate(final DBObject dbObject) {
dbObject.put("someTimestamp", new Date(dbObject.get("someTimestamp")));
}
有效果的东西应该能满足你的需要。这种方法有一些缺点
在这种情况下,你必须在每个领域都这样做。因此,上面的“items”示例需要在@PreLoad
方法中使用类似的代码。希望这种情况不会经常发生,所以不应该太麻烦
这是一个懒惰的转换。如果您有依赖于属性为日期的查询,它们将找不到尚未转换的记录。一种解决方案是通过morphia简单地加载/保存每个项目。这可能会破坏对这些文档的其他写入,除非您对对象进行版本设置。或者您可以编写一些javascript在shell中运行,以加载这些文档,创建一个新的日期,并简单地将$set设置回该字段。(当然,您也可以使用morphia和一些低级java驱动程序代码执行类似的操作)。如果不启用版本控制,这些解决方案中的任何一个都可能需要一些停机时间,具体取决于您的应用程序及其使用情况
希望这能让你朝着正确的方向开始。祝您好运。听起来您需要注释驱动的转换。第6.6.2节讨论了格式化程序,甚至有一个带有时间戳的示例
一般的想法是,您应该标记需要使用注释进行特殊处理的字段(这是注释的一个很好的用途,毕竟您正在指定元数据)。然后为具有该注释的字段注册一个转换器
问题是我刚刚尝试了这个,但无法让它工作,因为元数据正在丢失。我已经提交了一份报告,看看是否有办法解决这个问题。解决方案之一是使用spring data mongodb listener:
package com.rc.user.auth.model.listener;
import com.mongodb.DBObject;
import com.nimbusds.jwt.JWTParser;
import com.rc.user.auth.model.OAuth2AccessTokenEntity;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
import org.springframework.stereotype.Component;
import java.text.ParseException;
@Component
public class OAuth2AccessTokenEntityListener extends AbstractMongoEventListener<OAuth2AccessTokenEntity> {
@Override
public void onBeforeSave(BeforeSaveEvent<OAuth2AccessTokenEntity> event) {
OAuth2AccessTokenEntity oat = event.getSource();
DBObject db = event.getDBObject();
db.put("tokenValue", oat.getJwt().serialize());
}
@Override
public void onAfterConvert(AfterConvertEvent<OAuth2AccessTokenEntity> event) {
OAuth2AccessTokenEntity oat = event.getSource();
DBObject db = event.getDBObject();
try {
oat.setJwt(JWTParser.parse(db.get("tokenValue").toString()));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
package com.rc.user.auth.model.listener;
导入com.mongodb.DBObject;
导入com.nimbusds.jwt.JWTParser;
导入com.rc.user.auth.model.OAuth2AccessTokenEntity;
导入org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
导入org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
导入org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
导入org.springframework.stereotype.Component;
导入java.text.ParseException;
@组成部分
公共类OAuth2AccessTokenEntityListener扩展了AbstractMongoEventListener{
@凌驾
公共void onBeforeSave(beforesavevent事件){
OAuth2AccessTokenEntity oat=event.getSource();
DBObject db=event.getDBObject();
put(“tokenValue”,oat.getJwt().serialize());
}
@凌驾
AfterConvert上的公共无效(AfterConvertEvent事件){
OAuth2AccessTokenEntity oat=event.getSource();
DBObject db=event.getDBObject();
试一试{
setJwt(JWTParser.parse(db.get(“tokenValue”).toString());
}捕获(解析异常){
e、 printStackTrace();
}
}
}
解决方案二是使用变频器:
package com.rc.user.auth.model.convert;
import com.nimbusds.jwt.JWT;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;
@WritingConverter
public class JWTToStringConverter implements Converter<JWT, String> {
@Override
public String convert(JWT jwt) {
return jwt.serialize();
}
}
package com.rc.user.auth.model.convert;
进口com.nimbusds.jwt.jwt;
导入org.springframework.core.convert.converter.converter;
导入org.springframework.data.convert.WritingConverter;
@写转换器
公共类JWTToString Converter实现转换器{
@凌驾
公共字符串转换(JWT-JWT){
返回jwt.serialize();
}
}
从Spring Data MongoDB 3.2开始,似乎无法轻松定义特定于字段(而非全局)的类型转换器
配置bean中的方法影响所有域对象
但是您可以使用一个简单的变通方法,使用不同类型的字段和访问器方法(getter/setter)来完成您想要的
公共类人物{
@AccessType(AccessType.Type.FIELD)
私有即时时间戳;
公共长getTimestamp(){
返回这个.timestamp.getEpochSecond();
}
公共无效设置时间戳(最终长ts){
this.timestamp=瞬间秒(ts);
}
}
在上面的代码中,MongoDB的持久性映射器将看到java.time.Instant
type
字段和timestamp
字段将映射到MongoDB中的Date
(ISODate
)类型
但是,其他Java程序将通过long
类型访问Person.timestamp
字段,因为getter和setter使用long
类型
尽管这种方法不太喜欢使用字段级注释(如果存在),但它简单直观
是Java8之后日期/时间的基本类之一。它似乎最适合f
package com.rc.user.auth.model.convert;
import com.nimbusds.jwt.JWT;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;
@WritingConverter
public class JWTToStringConverter implements Converter<JWT, String> {
@Override
public String convert(JWT jwt) {
return jwt.serialize();
}
}