【Java】elasticsearch 整合springboot 的时候出现了日期格式转换的问题 ,找了好多也没有解决,请大佬帮助
实体类字段
@Field( type = FieldType.Date,format = DateFormat.custom,pattern = "yyyy-MM-dd HH:mm:ss"
)
@JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createTcime;
测试类
@Testpublic void TestSearch(){
//构造查询条件
NativeSearchQuery searchQuery =new NativeSearchQueryBuilder()
//QueryBuilders 帮助类 multiMatchQuery 多条件匹配 第一个参数时要查询的文本 ,第二个参数时在那个字段里查询
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬","title","content"))
//排序 按照type 这个字段排序,排序方式为倒叙
.withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
//分页
.withPageable(PageRequest.of(0,10))
//结果高亮显示
.withHighlightFields(
//高亮显示的字段 设置显示的标签
new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
).build();
//查询
Page<DiscussPost> search = discussPostRepository.search(searchQuery);
System.out.println(search.getTotalElements()); //一共多少条数据
System.out.println(search.getTotalPages()); //一共多少页
System.out.println(search.getNumber());//当前在第几页
System.out.println(search.getSize());//每页几条数据
for (DiscussPost post : search) {
//查看具体的数据
System.out.println(post);
}
}
错误信息
java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {YearOfEra=2019, MonthOfYear=4, DayOfMonth=25},ISO resolved to 10:14:05 of type java.time.format.Parsedat java.time.Instant.from(Instant.java:378)
at org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter.parse(ElasticsearchDateConverter.java:125)
at org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentProperty$1.read(SimpleElasticsearchPersistentProperty.java:160)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.readValue(MappingElasticsearchConverter.java:281)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$ElasticsearchPropertyValueProvider.getPropertyValue(MappingElasticsearchConverter.java:867)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.readProperties(MappingElasticsearchConverter.java:260)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.readEntity(MappingElasticsearchConverter.java:192)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.read(MappingElasticsearchConverter.java:172)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.read(MappingElasticsearchConverter.java:81)
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadDocumentCallback.doWith(AbstractElasticsearchTemplate.java:602)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadSearchDocumentResponseCallback.doWith(AbstractElasticsearchTemplate.java:626)
at org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate$ReadSearchDocumentResponseCallback.doWith(AbstractElasticsearchTemplate.java:612)
at org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.search(ElasticsearchRestTemplate.java:272)
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.search(AbstractElasticsearchRepository.java:249)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:382)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:549)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy116.search(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy116.search(Unknown Source)
at com.mango.community.dao.elasticsearch.DiscussPostRepositoryTest.TestSearch(DiscussPostRepositoryTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
at java.time.format.Parsed.getLong(Parsed.java:203)
at java.time.Instant.from(Instant.java:373)
... 113 more
回答
这个bug是哪一个版本的呢?我也是遇到这个问题,用Date,能写入,不能转出
2020-11-04更新
这次直接整一个视频来,之前回答的稍微有点乱了,如果没看懂可以看看我录的解说视频叭(不过貌似声音有点小。。。)
https://www.bilibili.com/vide...
2020-10-16 更新
今天又要更新一下,昨天的回答最后不是提到我去spring data elasticsearch
提了一个issues,还怕被那边大佬打脸说不是问题,经过昨晚大佬简短的确认问题,今天北京时间凌晨4点,大佬复现了问题,并且做了代码修改
也就是说,这确实是一个bug,而且修改方法也是按照我15号更新的方式去修改的,奈斯啊(这是spring data elasticsearch代码提交记录)
也就是说String -> TemporalAccessor
后一定要经历过一次再转ZonedDateTime
之后,才能转成Instant
,不过呢,spring data elasticsearch
还没有发版本,所以想要同样的修改,还是可以按照15号我的方式做也行哦╰(_°▽°_)╯
2020-10-15 更新
昨天的回答,确实很牵强,毕竟不是按照题主的需求来做的修改,我今天再看了一下,终于自己确认了一些问题同时也暂时找到一个可以实现题主要求的方式
确认的问题:
spring data elasticsearch
在处理实体属性类型为java.util.Date
的read
操作上有问题,也就是应该有bug,其实也就是在ElasticsearchDateConverter.parse
的方法处理上
这个我在昨天初次回答的时候已经提到,有问题的地方就在于dateFormatter.parse(input)
出来的结果TemporalAccessor
被Instant.from
调用失败,但当时我没有仔细想,而是想办法去绕过,所以才有了昨天的回答
实现题主需求的方法:
我们忽略了一个问题就是,时间转换上,spring data elasticsearch
其实都用的DateTimeFormatter
,也就是无论是String -> Date
还是Date -> String
都是采用DateTimeFormatter
的方法,那既然能够写入,读出应该也是可以的,毕竟DateTimeFormatter
可是jdk
自带的时间格式化工具,不可能说它只实现了一半功能,所以说,现在读出不行,写入可以,说明spring data elasticsearch
在使用DateTimeFormatter
时,写入时传入的参数正确,读出时传入的参数错误,所以我们也就可以去比对一下它们两个过程到底怎么做的,有什么区别。首先现在我们理清spring data elasticsearch
处理过程大体为:
写入:Date -> Instant(TemporalAccessor) -> String
读出:String -> Parese(TemporalAccessor) -> Instant(TemporalAccessor) -> Date
不过再一次仔细看完写入的代码发现,其实Instant(TemporalAccessor)
不是直接到String
Instant(TemporalAccessor)
还经历了一次DateFormatters.from
,
该方法是把一个TemporalAccessor
转换为ZonedDateTime
,再由ZonedDateTime
转换成String
,此时写入过程变为
写入:Date -> Instant(TemporalAccessor) -> ZonedDateTime(TemporalAccessor) -> String
这下也就释然了,为啥呢?因为java.util.Date
在功能上就是和新的java8
时间API
的ZonedDateTime
差不多的,这样的转换也是合理的。
反过来看读出时并没有这一步操作啊,其实这就不合理了,为啥呢?比如es里存的时间格式恰好没有时分秒,只有年月日,那它该怎么从一个年月日转换为Date
呢?必须要补齐时分秒啊,这一步操作没有的话,是不能把TemporalAccessor
转化为一个Instant
的,Instant
可是一个时间戳
所以正确的读出的过程应该是这样:
String -> Parese(TemporalAccessor) -> ZonedDateTime(TemporalAccessor) -> Instant(TemporalAccessor) -> Date
所以如果我们能把ElasticsearchDateConverter.parse
的处理改为下面这样就可以了
为了达到这个效果,我们捋捋,同时去寻找spring data elasticsearch
的扩展能力。
- 首先是我们的目标位置
ElasticsearchDateConverter
没有托管给Spring
,它属于SimpleElasticsearchPersistentProperty
的一个处理过程new
出来的 SimpleElasticsearchPersistentProperty
也没有托管给Spring
,它属于SimpleElasticsearchMappingContext
,终于这个Context
是被托管的,且有可扩展点
在ElasticsearchDataConfiguration
中我们可以看到扩展点配置
所以我们只需要去
- 补一个
SimpleElasticsearchMappingContext
的Bean
覆盖默认的,简单取名为CustomSimpleElasticsearchMappingContext
- 而
CustomSimpleElasticsearchMappingContext
中要使用新的CustomSimpleElasticsearchPersistentProperty
,而不是之前的SimpleElasticsearchPersistentProperty
- 然后
CustomSimpleElasticsearchPersistentProperty
要使用的是CustomElasticsearchDateConverter
而不是ElasticsearchDateConverter
- 最后
CustomElasticsearchDateConverter
中修改parse
即可
不知道这里几个类如果没看源码可能会绕晕点,不过还不算复杂,只是线性的依赖,我简单梳理一个图描述一下修改的想法
由于三个类里面的东西比较多,我干脆甩到了github上,可以自行查阅
同时,由于我认为这也是一个bug,所以直接跑去spring data elasticsearch官网提了一个issues,我简单截一个图,其实就是用蹩脚的英语描述一下。。。
hhhhh,虽然不知道会不会被打脸。。。。后续他们有回答的话,我会再来更新。。。就酱(๑•̀ㅂ•́)و✧
2020-10-14回答
试了哈,确实有这样的问题,先说哈我最后牵强的解决方案...
你的createTime
字段修改一下,改为
@Field( type = FieldType.Date, format = DateFormat.date_hour_minute_second)@JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private LocalDateTime createTime;
也就是
format
改为date_hour_minute_second
,它是标准ISO 8601的时间表示方式,存入数据库的格式为yyyy-MM-dd'T'HH:mm:ss
,也就是比你之前的多了个T
- 数据类型由
Date
改为LocalDatetime
自己demo了一下是可以的,你可以试试看
至于为啥之前你这样写报错,原因说起来稍微复杂一点,我也是看了才知道
首先从报错入手,Instant.from
报错,这是还没有转成最终的Date
就失败了
那继续看出错具体原因为,在当前类的getLong
方法中,也就是当前类不支持Instant
传给它的Field
而当前类就是Instant.from
的入参TemporalAccessor
,此时实现为Parsed
,虽然Parsed
它也是一个TemporalAccessor
,跟我们平常了解到的LocalDate
或LocalDateTime
稍有不一样,但是都是TemporalAccessor
,也就是都是时间的一个访问方式,只是它侧重于时间数据被parse
后的存储,我个人理解为就是一种中间过程类,并不适合我们用,是DateTimeFormatter
解析日期字符串后的产物,然后我们再可以根据TemporalAccessor
的特性,query
出我们要的时间形式即可
也就是说只要用DateTimeFormatter
解析再加上用Instant
做转换,永远都会报错,那我们接着看源码,可以不可以转变这样的结果
那就是继续沿着堆栈继续往上看,来到SimpleElasticsearchPersistentProperty$1.read
这一行代码豁然开朗,因为这里有个重要的分支isTemporalAccessor
那TemporalAccessor
不用多说,是咱们的时间访问入口,所以这就可以很自然的接入到Java8的时间API里了
直接查看它的实现方式,很明显,用了TemporalAccessor
的from
方法,而这个是根据type
来的,不用多说,这个type
肯定就是实体类里定义的类型了
既然如此,我们就可以根据Java8的时间类型+题主业务需要来选择具体的TemporalAccessor
,那我首先想到的用LocalDateTime
一试结果还是报错
此时从这里看temporal
是Parsed
,所以根本原因就是Parsed
的query
方法返回的LocalDate
为空,而进入Parsed.query
其实就是因为Parsed
里的date
属性为空,那按照之前我们处理Instant
的方案来说,这也就改不了么?
不是的,因为此时情况不一样,我们回顾一下此时的情况LocalDateTime
的from
方法调用了一个DateTimeFormatter
解析后的结果Parsed
失败
???
为啥我会有问号,因为日常我用java8
时间api
解析时间,不就是这么做的么?
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");TemporalAccessor parse = dateTimeFormatter.parse("2020-10-14 11:12:39");
LocalDateTime localDateTime = LocalDateTime.from(parse);
写了一万遍了,突然说这个不行?显然不是啊,所以比对一下这个简单的处理过程,减去相同变量,根本原因那就是这个DateTimeFormatter
扫了一下源码,在DateFormatters.forPattern
中藏着所有秘密,这里就是具体的pattern
对应的DateFormatter
,一大堆if else
,太多了,简单截个小图吧
那咱们现在写的pattern
为yyyy-MM-dd HH:mm:ss
,根据这些if else
,恰好是最后一个else
注意这里的DateTimeFormatterBuilder
,根据后面的代码可知,这里的DateTimeFormatterBuilder
创建出来的DateTimeFormatter
为最终解析咱们createTime
的DateTimeFormatter
比对下我之前没有问题的写法,走入DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
其实为:
new DateTimeFormatterBuilder() .appendPattern(pattern)
.toFormatter()
而spring data Elasticsearch
里的为:
new DateTimeFormatterBuilder() .appendPattern(input)
.toFormatter(Locale.ROOT)
.withResolverStyle(ResolverStyle.STRICT))
也就是说它比我的多了一个Locale.ROOT
和ResolverStyle.STRICT
,通过简单的控制变量法把我之前的例子分别加上其中一个后,发现导致报错的是ResolverStyle.STRICT
这个ResolverStyle
代表解析日期和时间的程度,默认的是STRICT
也就是严格,而我之前的有没有选那就是SMART
智能
但从源码看起来,是没有机会修改这个ResolverStyle
,那我当时想到只能是改变一下我们自己了,也就是按照ISO 8601的标准日期和时间展示格式来存储,因为yyyy-MM-dd HH:mm:ss
并不是标准的
那既然是标准的,那DateFormat
肯定就不会是custom
,根据elasticsearch官网的说明
我最终采用了date_hour_minute_second
,之后再试了一下,就ok了
不过由于其实不算真正解决题主的问题,毕竟需求来说,最终数据库存储还是需要yyyy-MM-dd HH:mm:ss
的,我暂时也没有想到更好的方法,只是根据现有的线索算是临时方案吧,如果有更好的,可以@我一下我,那拜了个拜︿( ̄︶ ̄)︿
(题外的话:其实为啥我很有兴趣看下去,是我之前也整理过java8
时间api
的一些东西,尤其是接口设计方面,我尝试用自己的理解去解析时间api
,同时用自己的语言写出了《Java8 时间API及主要接口个人理解》,可以直接看第三部分Java8时间接口),当时只是对一些顶层接口有了点印象,不过今天其实还算是有很多收获,尤其是关于era
(世纪),不过era
我在刚的回答里没有提到,我的文章里其实也没有提到,但是这次最终为啥date_hour_minute_second
的方式又可以了,其实跟era
是或多或少有些关系的,因为最终date_hour_minute_second
里时间的field
为ChronoField.YEAR
,而之前错误的为ChronoField.YEAR_OF_ERA
)
我们之前项目也遇到过,我们用的简单的方式,把时间转换成时间戳,存long型
遇到一个类似的问题,代码中设置如下类型
@Field( type = FieldType.Date)private Date createTcime;
这时 es 中 mapping 字段类型为 date ,es实际存储的是 createTcime 的时间戳(long),今天发现当日期在 1970-01-25 15:20:00 之前(时间戳刚好对应 int 最大值2100000000),可以成功储存到es,并保存成时间戳,但是从es 查询数据回来映射java类时,会报 int 无法被转换为date. 而日期在 1970-01-25 15:20:00之后,读写es都是可以成功的。
猜想在进行对es返回数据转换java Date类 解析时 ,会判断是否满足long类型,满足就当时间戳解析,否则当int类型处理,所以报错了
解决方案
给es 的entityMapper添加一个int转date类型的convert,其中ElasticsearchConfig extends AbstractElasticsearchConfiguration
老哥,解决了吗这个问题,我也遇到这个问题了
以上是 【Java】elasticsearch 整合springboot 的时候出现了日期格式转换的问题 ,找了好多也没有解决,请大佬帮助 的全部内容, 来源链接: utcz.com/a/87024.html