如何使Spring Data Elasticsearch与java.time.LocalDateTime一起使用以获取日期

the*_*dam 5 java spring elasticsearch spring-data

我正在使用Spring Data对Elasticsearch的支持。这是时间戳字段映射:

@Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true,
        format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSSZZ")
private LocalDateTime timestamp;
Run Code Online (Sandbox Code Playgroud)

这导致Elasticsearch中的字段映射如下:

"timestamp":{"type":"date","store":true,"format":"yyyy-MM-dd'T'HH:mm:ss.SSSZZ"}
Run Code Online (Sandbox Code Playgroud)

当我使用java.util.Date时,一切正常。但是,当我如上所述切换到java.time.LocalDateTime时,发送到Elasticsearch的文档导致异常。这是文档(为简洁起见,时间戳字段):

"timestamp": {
    "hour":7, "minute":56, "second":9, "nano":147000000, "year":2017, "month":"FEBRUARY",
    "dayOfMonth":13, "dayOfWeek":"MONDAY", "dayOfYear":44, "monthValue":2, "chronology": {
        "id":"ISO", "calendarType": "iso8601"
    }
}
Run Code Online (Sandbox Code Playgroud)

和例外:

MapperParsingException[failed to parse [timestamp]]; nested: IllegalArgumentException[unknown property [hour]];
(...)
Caused by: java.lang.IllegalArgumentException: unknown property [hour]
Run Code Online (Sandbox Code Playgroud)

似乎在对文档进行json加密时,这里会忽略该模式。有任何提示吗?也许您可能知道如何在Spring Data中使用“内置” _timestamp字段?

Eri*_*Tan 8

我遇到了类似的问题:日期值中的“Z”被视为字符,因此日期解析失败。我的解决方案是使用自定义模式来确保转换正确:

@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private LocalDateTime dateField;
Run Code Online (Sandbox Code Playgroud)

如果我们不想在不同的字段上一次又一次地重复该模式,我们可以尝试集中化转换逻辑。Spring Data Elastic Search 提供自定义转换功能,请查看此处的示例。

基本上我们可以编写一个从 String 到 LocalDateTime 的转换器,并将日期模式放在那里。


Ced*_*ult 6

检查https://github.com/spring-projects/spring-data-elasticsearch/wiki/Custom-ObjectMapper添加JavaTimeModule到您的中ObjectMapper

@Configuration
public class ElasticSearchConfiguration {

  @Bean
  public ElasticsearchTemplate elasticsearchTemplate(Client client) {
    return new ElasticsearchTemplate(client, new CustomEntityMapper());
  }

  public static class CustomEntityMapper implements EntityMapper {

    private final ObjectMapper objectMapper;

    public CustomEntityMapper() {
      objectMapper = new ObjectMapper();
      objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
      objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
      objectMapper.registerModule(new CustomGeoModule());
      objectMapper.registerModule(new JavaTimeModule());
    }

    @Override
    public String mapToString(Object object) throws IOException {
      return objectMapper.writeValueAsString(object);
    }

    @Override
    public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
      return objectMapper.readValue(source, clazz);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这看起来很有希望。默认情况下不使用 JavaTimeModule 的任何原因 (2认同)