0. 引言
在使用spring-data-elasticsearch读取es中时间类型的数据时出现了日期转换报错,不少初学者会在这里困惑很久,所以今天我们专门来解读该问题的几种解决方案。

1. 问题分析
该问题的报错形式一般是:

Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2022-03-15T14:31:55+08:00';
nested exception is java.lang.IllegalArgumentException"

当然时间类型的表现形式不一定是我这里的2022-03-15T14:31:55+08:00,可能多种多样,但解决办法都是一致的。

该问题的原因很简单,就是es中存储的时间格式是该种类型的,使用java client去获取时,无法直接转换为时间类型

2. 问题解决
这里演示的环境版本是如下所示。如果在实操时发现部分代码不可用,注意检查版本

spring-data-elasticsearch3.2.12.RELEASE

2.1 es mapping与实体类中声明相同的时间格式
第一种方案,是我们应该在实体类和索引mapping创建前就做好的,将es mapping中的时间字段的格式与实体类中保持统一
1、es mapping中设置时间格式,如果有多种格式中间用||隔开

PUT date_custom
{
"mappings": {
"properties": {
"create_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00' || strict_date_optional_time || epoch_millis"
}
}
}
}

2、实体类中同样声明该时间格式

@Data
@Document(indexName = "date_custom",shards = 1, replicas = 0)
public class DateTest implements Serializable { @Field(type = FieldType.Date, name = "create_time",format = {},
pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00' || strict_date_optional_time || epoch_millis")
private Date createTime; // 旧版本
// @Field(type = FieldType.Date, name = "create_time",format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00' || strict_date_optional_time || epoch_millis")
// private Date createTime;
}

es自带的时间格式,可以在官方文档中找到

2.2 配置日期格式转换器
1、ElasticsearchRestTemplate的构造方法中提供了一个构造方法,可以传入指定的EntityMapper

@Bean
public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient elasticsearchClient,EntityMapper entityMapper){
return new ElasticsearchRestTemplate(elasticsearchClient,entityMapper);
}

2、EntityMapper有两个实现类,其中ElasticsearchEntityMapper实现类提供了一个自定义转换器的方法setConversions

@Bean
@Override
public EntityMapper entityMapper() {
ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}

3、通过该方法我们可以将我们自定义的转换器StringToDateConverter传入进去

@Override
public ElasticsearchCustomConversions elasticsearchCustomConversions(){
List<Converter<?,?>> converterList = Lists.newArrayList(StringToDateConverter.INSTANT);
return new ElasticsearchCustomConversions(converterList);
}

4、完整代码

import com.google.common.collect.Lists;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchEntityMapper;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.EntityMapper;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.NonNull; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; @Configuration
@EnableElasticsearchRepositories(basePackages = "com.example.datedemo")
public class ElasticRestClientConfig extends AbstractElasticsearchConfiguration { @Value("${spring.elasticsearch.rest.uris}")
private String url;
@Value("${spring.elasticsearch.rest.username}")
private String username;
@Value("${spring.elasticsearch.rest.password}")
private String password; @Override
@Bean
public RestHighLevelClient elasticsearchClient() {
url = url.replace("http://","");
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username,password);
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(url)
.withDefaultHeaders(headers)
.build();
return RestClients.create(clientConfiguration).rest();
} @Bean
public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient elasticsearchClient,EntityMapper entityMapper){
return new ElasticsearchRestTemplate(elasticsearchClient,entityMapper);
} /**
* 指定EntityMapper为ElasticsearchEntityMapper
* 解决es mapper映射实体类问题
* @return
*/
@Bean
@Override
public EntityMapper entityMapper() {
ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
} /**
* 指定日期转换器,解决日期转换错误问题
* @return
*/
@Override
public ElasticsearchCustomConversions elasticsearchCustomConversions(){
List<Converter<?,?>> converterList = Lists.newArrayList(StringToDateConverter.INSTANT);
return new ElasticsearchCustomConversions(converterList);
} /**
* 字符串转换日期
*/
private enum StringToDateConverter implements Converter<String, java.util.Date> {
/**
* 转换器实例
*/
INSTANT; @Override
public Date convert(@NonNull String source) {
try {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'+08:00'").parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
} }

2.3 @DateTimeFormat注解声明格式(不生效)
首先说明一下这种方式并不生效,这里单独说明是为了列举出来,让大家避免走弯路。

该种方法的原理是通过在注解中声明自定义格式来实现格式转换,但实际上这并不起作用,因为spring-data-elasticsearch会忽略@DateTimeFormat注解

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") //返回时间类型
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") //接收时间类型
private Date startTime;

================
1、my es mapping

PUT test001
{
"mappings": {
"properties": {
"order_count": {
"type": "long"
},
"pay_amount_sum": {
"type": "double"
},
"shop_id": {
"type": "long"
},
"statistic_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss || strict_date_optional_time || epoch_millis"
}
}
}
}

2、my java model code

   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Field(value = "create_time", type = FieldType.Date, format = DateFormat.epoch_millis)
private Date createTime;

3、my exception

Unable to convert value '2022-05-23 14:49:24' to java.util.Date for property 'createTime'

4、my change

 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Field(value = "create_time", type = FieldType.Date, format = {},
pattern = "yyyy-MM-dd HH:mm:ss || strict_date_optional_time || epoch_millis")
private Date createTime;

Elastic实战:彻底解决spring-data-elasticsearch日期、时间类型数据读取报错问题的更多相关文章

  1. spring data elasticsearch 使用

    很久之前就安装了elasticsearch,一直没用java用过,最近看了一下spring data系列的elasticsearch,这里写一篇心得. 如果尚未安装elasticsearch,可以 参 ...

  2. SqlServer数据库表导入SqlLite数据库表保持日期时间类型字段的格式

    在写查询功能的过程中遇到一个这样的问题:按日期范围查询,sql语句是:where dt>=用户选择起始日期&&dt<=用户选择结束日期.数据库中的数据如图1,我选择的测试数 ...

  3. 3.4_springboot2.x整合spring Data Elasticsearch

    Spring Data Elasticsearch 是spring data对elasticsearch进行的封装. 这里有两种方式操作elasticsearch: 1.使用Elasticsearch ...

  4. SprignBoot整合Spring Data Elasticsearch

    一.原生java整合elasticsearch的API地址 https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java ...

  5. elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)

    一.ES Client 简介 1. ES是一个服务,采用C/S结构 2. 回顾 ES的架构 3. ES支持的客户端连接方式 3.1 REST API ,端口 9200 这种连接方式对应于架构图中的RE ...

  6. Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)

    elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介.Java REST Client.Java Client.Spri ...

  7. Spring Data Elasticsearch 用户指南

    https://www.jianshu.com/p/27e1d583aafb 翻译自官方文档英文版,有删减. BioMed Central Development Team version 2.1.3 ...

  8. Elasticsearch基本用法(2)--Spring Data Elasticsearch

    Spring Data Elasticsearch是Spring Data项目下的一个子模块. 查看 Spring Data的官网:http://projects.spring.io/spring-d ...

  9. Spring Boot + Spring Data + Elasticsearch实例

    Spring Boot + Spring Data + Elasticsearch实例 学习了:https://blog.csdn.net/huangshulang1234/article/detai ...

  10. elasticsearch 拼音+ik分词,spring data elasticsearch 拼音分词

    elasticsearch 自定义分词器 安装拼音分词器.ik分词器 拼音分词器: https://github.com/medcl/elasticsearch-analysis-pinyin/rel ...

随机推荐

  1. eclipse安装UML插件

    安装AmaterasUML AmaterasUML 是一个用于 Eclipse 的轻量级 UML 和 ER 图编辑器. 将AmaterasUML的3个jar包拷到Eclpise的plugins文件下: ...

  2. 02-Redis系列之-架构和高级API的使用

    通用部分 通用命令 # 1-keys # 打印出所有key keys * # 打印出所有以n开头的key keys n* # 打印出所有以nam开头,第四个字母是a到z的范围 keys nam[a-z ...

  3. Codeforces Round 734 (Div. 3)B2. Wonderful Coloring - 2(贪心构造实现)

    思路: 分类讨论: 当一个数字出现的次数大于等于k,那么最多有k个能被染色, 当一个数字出现的次数小于k,南那么这些数字都可能被染色 还有一个条件就是需要满足每个颜色的数字个数一样多,这里记出现次数小 ...

  4. B. Ela's Fitness and the Luxury Number

    思路: \[能想到平方是比较特殊的,因为x*x一定是x的倍数也就是说\sqrt[2]{x*x} = {x} \] \[所以需要考虑平法之间的数手模一下样例可以发现 [x^2 ,(x+1)^2)之间是x ...

  5. XAF新手入门 - 视图布局示例

    前言 掌握了应用程序模型(ApplicationModel)的基础知识之后,通过一个视图布局示例来加强对应用程序模型的理解. 官网给出了比较丰富的示例,并且这些示例涵盖了应用程序模型操作的方方面面,通 ...

  6. jQuery 框架

    jQuery 框架 目录 jQuery 框架 一. 概述 二. jQuery 安装引用 2.1 安装 2.2 本地导入使用 2.3 jQuery CDN引入 三. jQuery基本语法 四. 查找标签 ...

  7. 我为什么使用Linux做开发

    系统选择 目前市面上主流的桌面操作系统在大多数人眼里只有Windows和MacOS,那为什么我没选择它们两呢? 首先,不选MacOS的原因,就是太贵.当然这是我的原因不是苹果的原因,我最早使用Linu ...

  8. mybatis使用postgresql中的jsonb数据类型

    最近新开发的一个功能使用到postgresql中的jsonb数据类型.架构师可能考虑到这种数据格式更加便于存储json格式的数据,因此考虑使用这种数据类型.自己以前未曾使用过这种数据类型,因此需要现学 ...

  9. FreeRTOS教程4 消息队列

    1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) Keil µVision5 IDE(MDK-Arm) 野火DAP仿真器 XCO ...

  10. 基于恒玄WT250芯片的蓝牙辅听耳机方案调试总结

    前记 在蓝牙辅听领域卷了几年之后.各种型号的蓝牙辅听器都做过.这次,客户需要一款性价比超高的蓝牙辅听器.经过成本以及功能考量的筛选.最终定下来使用wt250来做一款低成本的蓝牙辅听器. 硬件部分 wt ...