>

java.util.Date 가있는 Java 객체를 유지하려고합니다. fasterxml jackson을 사용하는 몽고 컬렉션의필드 objectMapper의 기본 특성은 Date를 NumberLong 유형으로 저장하는 것입니다.

예 : createdTime java.util.Date필드 유형은 다음과 같이 저장됩니다 :

"createdTime" : NumberLong("1427728445176")

몽고 쉘에서 사용할 수있는ISODate형식으로 저장하고 싶습니다.

이제 객체 매퍼를 포맷하여 날짜를 문자열 날짜 형식으로 저장하는 방법이 있다는 것을 알고 있습니다. 하지만 ISODate () 형식 만 찾고 있습니다.

예 : "createdTime" : ISODate("2015-01-20T16:39:42.132Z")

할 수있는 방법이 있습니까? 전문가에게 조언하십시오. 도움을 주셔서 감사합니다.

  • 답변 # 1

    필요한 것은 Jackson Joda Module입니다. 클래스 패스로 가져 오면 매퍼에서 다음을 수행하여 원하는 타임 스탬프로 쓸 수 있습니다.

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JodaModule());
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
    mapper.writeValueAsString(date);
    
    

    date 를 교체 할 수 있습니다  필요에 따라 위의 코드 샘플에서 POJO를 사용하십시오.

    편집 : 실제로 원하는 것은 사용자 정의 직렬 변환기입니다. 다음과 같이 보일 것입니다 :

    public class IsoDateSerializer extends JsonSerializer<DateTime> {
        @Override
        public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) {
            String isoDate = ISODateTimeFormat.dateTime().print(value);
            jgen.writeRaw("ISODATE(\"" + isoDate + "\")");
        }
    
    

    그러면 모든 DateTime 유형에 대해 매퍼에 등록합니다

    mapper.addSerializer(DateTime.class, new IsoDateSerializer());
    
    

    주석을 사용하여 함수에 지정

    @JsonSerializer(using = IsoDateSerializer.class)
    public DateTime createdTime;
    
    

  • 답변 # 2

    날짜 문자열을 ISODate 형식으로 직렬화 할 수있었습니다. 아래와 같이 고객 날짜 시리얼 라이저를 작성했습니다.

    public void serialize(Date date, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        String dateValue = getISODateString(date);
        String text = "{ \"$date\" : \""+   dateValue   +"\"}";
        jgen.writeRawValue(text);
    }
    
    

    사용자 @ mmx73의 요청에 따라 고객 날짜 DeSeriaizer에 대한 코드를 추가하고 있습니다.

    public class IsoDateDeSerializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                throws IOException, JsonProcessingException {
            ObjectCodec oc = jsonParser.getCodec();
            JsonNode node = oc.readTree(jsonParser);
            String dateValue = node.get("$date").asText();
            //DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            Date date = null;
            try {
                 date = df.parse(dateValue);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    
    

  • 답변 # 3

    이 답변들 중 어느 것도 내가 원하는 것을 성취하지 못했습니다. JSON 문자열을 MongoDB에 직렬화 할 때 문자열로 저장 되었기 때문에 문제가 발생했습니다. 좋은 형식의 문자열이지만 문자열은 적습니다.

    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
    
    

    MONGODB로 전송 될 JSON은 "$date"라는 필드를 포함하는 값을 정의합니다. 이것은 MongoDB에게 이것이 날짜 개체라고 알려줍니다.

    Mongo를 보면 다음이 표시됩니다.

    "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 유형입니다. ) 날짜 개체는 형식이 지정된 텍스트 문자열이 아닌 긴 값으로 저장됩니다. 이런 식으로 포맷 한 후 데이터를 mongo로 푸시 할 수 있는지 확인하지 않았지만 다음과 같이 지원하도록 위에 표시된 deserializer를 수정할 수 있습니다.

       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);
            }
        }
    });
    
    

    다음과 같이 밀리 초를 Date 또는 DateTime으로 변환 할 수 있습니다.

       /**
     * 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);
    }
    
    

  • 답변 # 4

    같은 메시지가 나타나는 경우

    com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value .

    writeRawValue 를 사용하십시오  대신 허용 된 답변 내에서. 필드가 올바르게 종료됩니다. 그렇지 않으면 직렬화 할 다음 필드에이 오류가 발생할 수 있습니다.

관련 자료

  • 이전 두 테이블 간의 장고 쿼리 공식화 문제
  • 다음 스프링 부트 2 (버전 200M7)에 Prometheus 지표를 포함 할 수 없음