這些答案都沒有完成我想要的。我遇到了麻煩,因爲當我將JSON字符串序列化到MongoDB時,它被存儲爲String。一個很好格式化的字符串,但一個字符串都不會少。
我使用com.fasterxml.jackson.databind.ObjectMapper將我的對象轉換爲/從JSON,我想繼續使用這個類。我有以下方法:
public enum JsonIntent {NONE, MONGODB};
public static ObjectMapper getMapper(final JsonIntent intent) {
ObjectMapper mapper = new ObjectMapper();
// Setting to true saves the date as NumberLong("1463597707000")
// Setting to false saves the data as "2016-05-18T19:30:52.000+0000"
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.registerModule(new JodaModule());
if (intent == JsonIntent.MONGODB) {
// If you want a date stored in MONGO as a date, then you must store it in a way that MONGO
// is able to deal with it.
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null, null, null));
testModule.addSerializer(Date.class, new StdSerializer<Date>(Date.class) {
private static final long serialVersionUID = 1L;
@Override
public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
try {
if (value == null) {
jgen.writeNull();
} else {
jgen.writeStartObject();
jgen.writeFieldName("$date");
String isoDate = ISODateTimeFormat.dateTime().print(new DateTime(value));
jgen.writeString(isoDate);
jgen.writeEndObject();
}
} catch (Exception ex) {
Logger.getLogger(JsonUtil.class.getName()).log(Level.SEVERE, "Couldn't format timestamp " + value + ", writing 'null'", ex);
jgen.writeNull();
}
}
});
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(Date.class) {
private static final long serialVersionUID = 1L;
@Override
public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
JsonNode tree = jp.readValueAsTree();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
try {
return ISODateTimeFormat.dateTime().parseDateTime(tree.get("$date").textValue()).toDate();
} catch (Throwable t) {
throw new IOException(t.getMessage(), t);
}
}
});
mapper.registerModule(testModule);
}
return mapper;
}
現在,我可以運行下面的測試代碼:
BObjectMapper mapper = getMapper(JsonUtil.JsonIntent.NONE);
Date d1 = new Date();
String v = mapper.writeValueAsString(d1);
System.out.println("Joda Mapping: " + v);
Date d2 = mapper.readValue(v, Date.class);
System.out.println("Decoded Joda: " + d2);
mapper = getMapper(JsonUtil.JsonIntent.MONGODB);
v = mapper.writeValueAsString(d1);
System.out.println("Mongo Mapping: " + v);
d2 = mapper.readValue(v, Date.class);
System.out.println("Decoded Mongo: " + d2);
輸出如下:
Joda Mapping: "2016-06-13T14:58:11.937+0000"
Decoded Joda: Mon Jun 13 10:58:11 EDT 2016
Mongo Mapping: {"$date":"2016-06-13T10:58:11.937-04:00"}
Decoded Mongo: Mon Jun 13 10:58:11 EDT 2016
注意,JSON,這將是發送到MONGODB定義的值包含一個名爲「$ date」的字段。這告訴MongoDB這是一個看起來像日期的對象。
當我看着蒙戈,我看到以下內容:
"importDate" : ISODate("2016-05-18T18:55:07Z")
現在,我可以訪問該字段爲日期,而不是作爲一個字符串。
所編碼的JSON字符串添加到蒙戈,我的代碼如下:
MongoDatabase db = getDatabase();
Document d = Document.parse(json);
db.getCollection(bucket).insertOne(d);
在這種情況下,「JSON」是編碼的JSON字符串。因爲它來自JSON字符串,除非它推斷出這種類型,否則無法知道類型,這就是爲什麼我們需要「$ date」部分。 「桶」只是一個指示要使用哪個表的字符串。
作爲一個提示,我發現如果我從Mongo中取出一個BSON對象,並通過調用doc.toJson()將其轉換爲JSON字符串(其中doc的類型爲org.bison.Document,查詢)時,日期對象以長整型值存儲,而不是格式化文本字符串。我沒有檢查,看看我是否可以用這種方式格式化後的數據推入蒙戈,但是,你可以按如下修改如上圖所示,以支持該解串器:
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(Date.class) {
private static final long serialVersionUID = 1L;
@Override
public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
JsonNode tree = jp.readValueAsTree();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
try {
// Mongo will return something that looks more like:
// {$date:<long integer for milliseconds>}
// so handle that as well.
JsonNode dateNode = tree.get("$date");
if (dateNode != null) {
String textValue = dateNode.textValue();
if (!Util.IsNullOrEmpty(textValue)) {
return ISODateTimeFormat.dateTime().parseDateTime(textValue).toDate();
}
return Util.MillisToDate(dateNode.asLong());
}
return null;
} catch (Throwable t) {
Util.LogIt("Exception: " + t.getMessage());
throw new IOException(t.getMessage(), t);
}
}
});
可以毫秒轉換爲日期或日期時間如下:
/**
* Convert milliseconds to a date time. If zero or negative, just return
* null.
*
* @param milliseconds
* @return
*/
public static Date MillisToDate(final long milliseconds) {
if (milliseconds < 1) {
return null;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliseconds);
return calendar.getTime();
}
public static DateTime MillisToDateTime(final long milliseconds) {
if (milliseconds < 1) {
return null;
}
return new DateTime(milliseconds);
}
謝謝@xathien。我早就已經嘗試過這種方法,但採用這種方法,它本質上創建了一個字符串。 例如,在改變我的代碼映射器後,如下所示 ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JodaModule()); mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false); \t \t \t \t 輸出是如下 「createdTime」: 「2015-03-30T19:33:08.921Z」。 我正在尋找類似下面的格式。 「createdTime」:ISODate(「2015-01-20T16:39:42.132Z」)\t \t 或者我錯過了什麼? – vishy 2015-03-30 19:38:01
查看更新的答案。 – xathien 2015-03-30 19:54:36
感謝@xathien。我用我的答案更新了這篇文章,但接受你的回覆作爲答案,因爲它指出我正確的方向:) – vishy 2015-04-02 01:02:47