首页 > 其他分享 >Spring ElasticSearch Date

Spring ElasticSearch Date

时间:2023-06-28 18:23:01浏览次数:35  
标签:return 定义 ElasticsearchRestTemplate Spring bean ElasticSearch Date public es

问题背景

使用spring-data-elasticsearch:4.4.12查询数据,数据映射到对象的时候时间字段格式异常,报错如下

对象和Es通过@document注解进行映射,对象中有一个时间字段

    @Field(type = FieldType.Date, format = {}, pattern = DatePattern.CHINESE_DATE_PATTERN)
    private Date createAt;

通过elasticEearchRestTemplate.save将数据保存到es的时候没有问题,但是通过.search方法读取数据的时候出现时间格式异常的问题

1. 定位问题

通过异常堆栈,定位到报错的源码位置


最后定位到是通过java.time.format.DateTimeFormatter#parse(java.lang.CharSequence, java.time.temporal.TemporalQuery)将es中"xxxx年xx月xx日"解析为java.util.Date是报错的
java.time是jdk1.8加入的时间处理类,同时加入的还有localDate、localDateTime,按照es源码中解析时间的代码,可以简单的将代码说明如下

因为使用了Instant去解析时间,Instant只解析年月日的时间格式会抛出异常,所以考虑这里能不能使用LocalDate去解析,或者将原始时间字符串改成年月日时分秒的格式。
需求决定Es中时间格式不能变,所以修改方案就只剩下了一种,使用LocalDate去解析时间字符串

2. 修改方案

第一种修改方案比较简单,将对象中Date类型字段改成LocalDate即可
第二种修改方案则是考虑修改es的格式转换代码,分析源码后发现
org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter被final修饰,所以不能实现子类
org.springframework.data.elasticsearch.core.convert.DatePropertyValueConverter中通过类名ElasticsearchDateConverter定义的属性,无法修噶
但是DatePropertyValueConverter实现了AbstractPropertyValueConverter接口,所以这里考虑重新实现AbstractPropertyValueConverter接口,并且实现该接口只需要实现两个方法,方案可行
最后将重新实现的类作为该方法的返回值即可org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentProperty#getPropertyValueConverter
具体代码如下

@Slf4j
@Configuration
public class ElasticRestClientConfig {

    @Bean
    public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient restHighLevelClient,
                                                               ElasticsearchConverter elasticsearchConverter) {
        return new ElasticsearchRestTemplate(restHighLevelClient, elasticsearchConverter);
    }

    @Bean
    public ElasticsearchRestTemplate myElasticsearchRestTemplate(RestHighLevelClient restHighLevelClient) {
        SimpleElasticsearchMappingContext simpleElasticsearchMappingContext = new SimpleElasticsearchMappingContext() {
            @Override
            protected ElasticsearchPersistentProperty createPersistentProperty(Property property, SimpleElasticsearchPersistentEntity<?> owner,
                                                                               SimpleTypeHolder simpleTypeHolder) {
                return new SimpleElasticsearchPersistentProperty(property, owner, simpleTypeHolder) {
                    @Override
                    public PropertyValueConverter getPropertyValueConverter() {
                        return new AbstractPropertyValueConverter(this) {
                            @Override
                            public Object write(Object value) {
                                // 该客户端仅用作从es读取数据,所以写方法不需要实现
                                log.error(">>>>>>>>>>>>>>>>>>>>>>>>>> es 写方法未实现");
                                return null;
                            }

                            @Override
                            public Object read(Object value) {
                                return DateUtil.parse(value.toString(), DatePattern.CHINESE_DATE_PATTERN);
                            }
                        };
                    }
                };
            }
        };

        ElasticsearchRestTemplate elasticsearchRestTemplate = new ElasticsearchRestTemplate(restHighLevelClient,
                new MappingElasticsearchConverter(simpleElasticsearchMappingContext));
        log.debug("自定义bean >>>>> {}", elasticsearchRestTemplate);
        return elasticsearchRestTemplate;
    }
}

使用的时候,用@autowire配合@Qualifier("myElasticsearchRestTemplate")指定使用自定义的bean即可

3. 后续

  1. 为什么这里要定义另外一个ElasticsearchRestTemplate?
    因为如果定义了ElasticsearchRestTemplate类型的bean,则jar包中原来的bean会失效,通过org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataConfiguration中定义bean是使用的注解
    @ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")我们知道,如果存在ElasticsearchOperations类型或者elasticsearchTemplate名称的bean时,
    jar包原来定义的bean会失效,因为我们自己定义的bean是ElasticsearchRestTemplate类型的,即实现了ElasticsearchOperations接口,所以,如果我们想使用jar中定义的bean,则需要重新定义一遍
  2. 另外一个问题,为什么我们只需要实现read方法,不需要实现write方法?
    因为我们这里只需要定义一个bean,从es中读取数据即可,写入数据我们使用jar包中原来定义的bean即可,所以不存在写的场景,自然不需要实现写的方法

标签:return,定义,ElasticsearchRestTemplate,Spring,bean,ElasticSearch,Date,public,es
From: https://www.cnblogs.com/raifujisann/p/17512207.html

相关文章

  • fastjson将date转换成了long
     记录一个bug,这个问题是使用fastjson的时候遇到了将date的数据转换成long类型而不是转换成string环境fastjson使用的是1.2.76造成的原因更具环境大家可能已经猜测到了真实的原因-版本太低造成的。这个项目的存在时间比较久所以在使用的依赖上版本比较低,除了源码之外......
  • Spring从基础到精通
    Spring从基础到精通(基础)spring的世界一、什么是springSpring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的,Spring致力于解决JavaEE的各层解决方案,而不仅仅于某一层的方案。二、spring发展历史2003年2月Spring框架正式称为一道开源项目,Spring致力于J2EE应......
  • Spring 赌上未来一击,推出响应式框架 WebFlux,代码更优雅,性能更强!
    Spring-webflux简介spring-webflux是spring在5.0版本后提供的一套响应式编程风格的web开发框架,大量测评证明,使用WebFlux开发接口能够大幅提升接口的吞吐量。这个框架包含了spring-framework和springmvc,它可以运行在Netty、Undertow以及3.1版本以上的Serlvet容器上。你可以在项......
  • 基于SpringBoot整合Redisson的延迟队列
    一、需求:     1.订单下单超过30分钟以后,如果还未支付,则自动转为取消支付状态 2.订单收货超过七天以后,如果还未评价,则自动转为好评 3.等类似需求二、实现步骤:    1. 引入redisson依赖<dependency><groupId>org.rediss......
  • Springboot实现邮件发送
    本文以QQ邮箱为例,实现springboot邮件发送邮箱设置 主要获取授权码   按照步骤开启服务 获取授权码导入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>配置......
  • ionic3安卓触发返回键ion-datetime不自动关闭
    框架:ionic3+angular机型:安卓问题:点击打开ion-datetime选择框,直接使用物理返回键(或自带的滑动返回)时,页面返回上一页但ion-datetime弹窗仍未关闭。理想情况:返回时会自动关闭ion-datetime弹窗再返回上一页解决方法://page.tsimport{Platform}from'ionic-angular';.........
  • Spring Boot:快速入门教程
      来源  https://www.cnblogs.com/xifengxiaoma/p/11019240.html  SpringBoot:快速入门教程......
  • Python time和datetime模块
    Pythontime和datetime模块标准库time与datetime时间的3中格式:时间戳时间戳-->struct_timetime.gmtime(UTC时间)time.localtime(本地时区时间)struct_time()struct_time-->时间戳time.mktimestruct_time-->格式化的字......
  • spring mvc 支持options方法
    在web.xml中,添加<init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param>添加后<servlet> <servlet-name>springdispatcher</servlet-name> <servle......
  • java8 LocalDateTime/LocalDate/LocalTime、java.util.Date/java.sql.Date区别及日期
    先介绍一下,LocalDateTime/LocalDate/LocalTime、java.util.Date/java.sql.Date区别LocalDateTime/LocalDate/LocalTimejava.time.LocalDateTime,是一个日期+时间,不带时区,它是个不可更改对象,精确到纳秒。它的日期可以认为是生日,它的时间可以认为是挂钟的时间,比较LocalDateTime时用eq......