Elastic实战:彻底解决spring-data-elasticsearch日期、时间类型数据读取报错问题
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日期、时间类型数据读取报错问题的更多相关文章
- spring data elasticsearch 使用
很久之前就安装了elasticsearch,一直没用java用过,最近看了一下spring data系列的elasticsearch,这里写一篇心得. 如果尚未安装elasticsearch,可以 参 ...
- SqlServer数据库表导入SqlLite数据库表保持日期时间类型字段的格式
在写查询功能的过程中遇到一个这样的问题:按日期范围查询,sql语句是:where dt>=用户选择起始日期&&dt<=用户选择结束日期.数据库中的数据如图1,我选择的测试数 ...
- 3.4_springboot2.x整合spring Data Elasticsearch
Spring Data Elasticsearch 是spring data对elasticsearch进行的封装. 这里有两种方式操作elasticsearch: 1.使用Elasticsearch ...
- SprignBoot整合Spring Data Elasticsearch
一.原生java整合elasticsearch的API地址 https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java ...
- 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 ...
- 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 ...
- Spring Data Elasticsearch 用户指南
https://www.jianshu.com/p/27e1d583aafb 翻译自官方文档英文版,有删减. BioMed Central Development Team version 2.1.3 ...
- Elasticsearch基本用法(2)--Spring Data Elasticsearch
Spring Data Elasticsearch是Spring Data项目下的一个子模块. 查看 Spring Data的官网:http://projects.spring.io/spring-d ...
- Spring Boot + Spring Data + Elasticsearch实例
Spring Boot + Spring Data + Elasticsearch实例 学习了:https://blog.csdn.net/huangshulang1234/article/detai ...
- elasticsearch 拼音+ik分词,spring data elasticsearch 拼音分词
elasticsearch 自定义分词器 安装拼音分词器.ik分词器 拼音分词器: https://github.com/medcl/elasticsearch-analysis-pinyin/rel ...
随机推荐
- Ubuntu/Centos下OpenJ9 POI输出Excel的Bug
项目更换 JDK为 OpenJ9 后, 使用 POI 导出 Excel 遇到的问题 OpenJ9 版本信息 /opt/jdk/jdk-11.0.17+8/bin/java -version openj ...
- STC MCU的软件和硬件PCA/PWM输出
软件方式输出PWM PWM用于输出强度的控制, 例如灯的亮度, 轮子速度等, STC89/90系列没有硬件PWM, 需要使用代码模拟 使用纯循环的方式实现PWM 非中断的实现(SDCC环境编译) #i ...
- 【Lua】Lua基础语法
1 Lua 简介 Lua 是一个小巧的脚本语言,用标准C语言编写而成,由巴西里约热内卢天主教大学的 Roberto Ierusalimschy.Waldemar Celes 和 Luiz Henr ...
- oracle sqlplus命令详解(官方示例)
以为内容选自Oracle官方文档,只讲command-line: 规范:<变量名> , {举例} , a | b 枚举可选值,(XX)描述 ------------------------ ...
- leetcode - 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同. 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的. 示例 1: 输入:p = [1,2,3], q = [1 ...
- 使用SecScanC2构建P2P去中心化网络实现反溯源
个人博客: xzajyjs.cn 前言 这款工具是为了帮助安全研究人员在渗透测试过程中防止扫描被封禁.保护自己免溯源的一种新思路.其利用到了区块链中的p2p点对点去中心化技术构建以来构建代理池. 工具 ...
- [Node] nvm 安装 node 和 npm
Node JS 安装 安装 node version manager (nvm) Windows: https://github.com/coreybutler/nvm-windows/release ...
- 【Azure 应用服务】App Service For Linux 中安装paping, 用于验证从App Service向外请求的网络连通性
问题描述 App Service For Linux 中安装paping的操作步骤 解决步骤 1) 登录App Service的Kudu站点,点击Bash 2)使用命令下载paping压缩文件:#wg ...
- 【Azure 应用服务】通过 Web.config 开启 dotnet 应用的 stdoutLog 日志,查看App Service 产生500错误的原因
问题描述 Web App(App Service) 经常出现500错误,但是通过高级管理工具(Kudu站点)查看了所有的日志,均没有定位到具体的原因,有那些方式可以查看到更多的信息呢? 问题解答 HT ...
- 【项目实战】SpringBoot+vue+iview打造一个极简个人博客系统
基于SpringBoot+vue+iview个人极简博客 项目介绍 个人极简博客 [个人极简博客]是一个适用于初学者学习的博客系统,其中包含文章分类.写文章.标签管理.用户管理等基础功能,代码简洁注释 ...