我正在将Spring Boot 2.1.4和Spring Data Jest与ElasticSearch结合使用。最初,我使用Java Date的某些属性带有以下注释:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSSZZ")
将其保存到ElasticSearch中,如下所示:
"creationDate": "2019-04-10T14:49:05.672+0000"
现在,我正在从Date迁移到LocalDateTime和ZonedDateTime。现在将数据保存到ElasticSearch时,将保存以下属性:
"creationDate": {
"dayOfYear": 123,
"dayOfWeek": "FRIDAY",
"month": "MAY",
"dayOfMonth": 3,
"year": 2019,
"monthValue": 5,
"hour": 11,
"minute": 54,
"second": 12,
"nano": 238000000,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
我需要做些什么来更改它,以便获得与LocalDateTime和ZonedDateTime相同的ElasticSearch数据格式?
我尝试了以下方法:
自定义对象映射器,如下所示:
public class CustomEntityMapper implements EntityMapper {
private final ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.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);
}
}
向对象映射器添加以下内容:
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
任何帮助或我出错的指针将不胜感激。
答案 0 :(得分:2)
那是因为spring-data-jest
使用DefaultEntityMapper
(Spring Data的一部分),它创建了自己的ObjectMapper
,而不使用Spring Boot提供的那个。可以在this related question中看到。
通过定义自己的EntityMapper
,例如CustomEntityMapper
,您将在解决方案的正确轨道上。但是,spring-data-jest
将此映射器包装到名为DefaultJestResultsMapper
的类中,然后由名为JestElasticsearchTemplate
的bean使用。
因此,可能您应该执行以下操作:
@Bean
public JestResultsMapper resultMapper(CustomEntityMapper entityMapper) {
return new DefaultJestResultsMapper(entityMapper);
}
@Bean
public JestElasticSearchTemplate template(JestClient client, JestResultsMapper resultsMapper) {
return new JestElasticSearchTemplate(client, resultsMapper);
}
这应该将您的CustomEntityMapper
注入到JestResultsMapper
中,然后又注入到框架使用的JestElasticSearchTemplate
中。
在CustomEntityMapper
中,您可以自动连线默认的ObjectMapper
(它将自动添加JavaTimeModule
),也可以自行配置一个。
答案 1 :(得分:1)
设法使其与Spring Boot 2.1.4和Spring Data Jest一起使用。这是我所做的:
示例域对象:
@Document(indexName = "datetest")
public class DateTest {
@Id
private String id;
@Field(type = FieldType.Date, 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", timezone = "UTC")
private Instant instant = Instant.now();
@Field(type = FieldType.Date, 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 ZonedDateTime zonedDateTime = ZonedDateTime.now();
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime localDateTime = LocalDateTime.now();
// getters/setters
}
ElasticSearch / JEST配置:
@Configuration
public class ESConfig {
@Bean
public EntityMapper getEntityMapper() {
return new CustomEntityMapper();
}
@Bean
@Primary
public ElasticsearchOperations elasticsearchTemplate(final JestClient jestClient,
final ElasticsearchConverter elasticsearchConverter,
final SimpleElasticsearchMappingContext simpleElasticsearchMappingContext, EntityMapper mapper) {
return new JestElasticsearchTemplate(jestClient, elasticsearchConverter,
new DefaultJestResultsMapper(simpleElasticsearchMappingContext, mapper));
}
public 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);
}
}
}
ElasticSearch中的结果:
希望这会有所帮助。
答案 2 :(得分:-1)
根据Spring Boot版本2的this answer,从java.time对象生成字符串方面,它应该可以立即使用
如果有
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0
作为依赖项,位于application.properties中的下一行
spring.jackson.serialization.write_dates_as_timestamps=false
因此,剩下的就是将时区表示法添加到默认字符串中了(没有)。
如果标准格式化程序对您不起作用,则可以始终编写自己的序列化器/解串器并按说明here进行附加