Elastic实战:彻底解决spring-data-elasticsearch日期、时间类型数据读取报错问题

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

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 配置文件设置spring.jackson.date-format

配置文件中设置时间类型格式,但这种方式全局生效,小心使用

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

2.4 单独创建日期类型转换类

@Component
public class DateConverter implements Converter<String, Date> {

    @Override
    public Date convert(@NonNull String source) {
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(source);
        } catch (ParseException e) {
            try {
                return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'+08:00'").parse(source);
            } catch (ParseException ex) {
                try {
                    return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(source);
                } catch (ParseException ex2) {
                    ex2.printStackTrace();
                }
            }
        }
        return null;
    }
}

2.5 @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;
相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。 &nbsp;
目录
相关文章
|
缓存 监控 前端开发
顺企网 API 开发实战:搜索 / 详情接口从 0 到 1 落地(附 Elasticsearch 优化 + 错误速查)
企业API开发常陷参数、缓存、错误处理三大坑?本指南拆解顺企网双接口全流程,涵盖搜索优化、签名验证、限流应对,附可复用代码与错误速查表,助你2小时高效搞定开发,提升响应速度与稳定性。
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
1817 2
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,日期时间格式化是前后端交互的常见痛点。本文详细解析了 **@DateTimeFormat** 和 **@JsonFormat** 两个注解的用法,分别用于将前端传入的字符串解析为 Java 时间对象,以及将时间对象序列化为指定格式返回给前端。通过完整示例代码,展示了从数据接收、业务处理到结果返回的全流程,并总结了解决时区问题和全局配置的最佳实践,助你高效处理日期时间需求。
2371 0
|
网络协议 Java Maven
多模块项目使用ElasticSearch报错
多模块项目使用ElasticSearch报错
437 9
|
存储 运维 监控
超越传统模型:从零开始构建高效的日志分析平台——基于Elasticsearch的实战指南
【10月更文挑战第8天】随着互联网应用和微服务架构的普及,系统产生的日志数据量日益增长。有效地收集、存储、检索和分析这些日志对于监控系统健康状态、快速定位问题以及优化性能至关重要。Elasticsearch 作为一种分布式的搜索和分析引擎,以其强大的全文检索能力和实时数据分析能力成为日志处理的理想选择。
1423 6
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
1038 0
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,处理前后端日期交互是一个常见问题。本文通过 **@DateTimeFormat** 和 **@JsonFormat** 两个注解,详细讲解了如何解析前端传来的日期字符串以及以指定格式返回日期数据。文章从实际案例出发,结合代码演示两者的使用场景与注意事项,解决解析失败、时区偏差等问题,并提供全局配置与局部注解的实践经验。帮助开发者高效应对日期时间格式化需求,提升开发效率。
4521 2
|
人工智能 自然语言处理 运维
让搜索引擎“更懂你”:AI × Elasticsearch MCP Server 开源实战
本文介绍基于Model Context Protocol (MCP)标准的Elasticsearch MCP Server,它为AI助手(如Claude、Cursor等)提供与Elasticsearch数据源交互的能力。文章涵盖MCP概念、Elasticsearch MCP Server的功能特性及实际应用场景,例如数据探索、开发辅助。通过自然语言处理,用户无需掌握复杂查询语法即可操作Elasticsearch,显著降低使用门槛并提升效率。项目开源地址:&lt;https://github.com/awesimon/elasticsearch-mcp&gt;,欢迎体验与反馈。
4198 1
|
消息中间件 Java Kafka
【Azure Kafka】使用Spring Cloud Stream Binder Kafka 发送并接收 Event Hub 消息及解决并发报错
reactor.core.publisher.Sinks$EmissionException: Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially.
432 6
|
前端开发 IDE Java
Spring MVC 中因导入错误的 Model 类报错问题解析
在 Spring MVC 或 Spring Boot 开发中,若导入错误的 `Model` 类(如 `ch.qos.logback.core.model.Model`),会导致无法解析 `addAttribute` 方法的错误。正确类应为 `org.springframework.ui.Model`。此问题通常因 IDE 自动导入错误类引起。解决方法包括:删除错误导入、添加正确包路径、验证依赖及清理缓存。确保代码中正确使用 Spring 提供的 `Model` 接口以实现前后端数据传递。
679 0

热门文章

最新文章