我正在尝试使用最新版本的弹性搜索库,它已经在maven repos中提供。
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.0.0</version>
</dependency>
但我不确定如何使用第7版的Spring Boot,它进口6.5版本。我对maven的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
如果有人在使用Spring Boot 2.1.2和Kotlin,下面的代码可能会对您有所帮助。我刚从@Alexander Lech answer翻译过来,有一些小改动:
首先更改为Alexanders答案:
@SpringBootApplication(exclude = [ElasticsearchAutoConfiguration::class,
ElasticsearchDataAutoConfiguration::class])
我必须排除ElasticsearchDataAutoConfiguration,才能让它工作。
第二:由于我们使用Kotlin,而且自定义转换器包含大量代码,因此对Kotlin的这种翻译可能会对某些人有所帮助:
class CustomElasticSearchConverter(mappingContext: MappingContext<out ElasticsearchPersistentEntity<*>, ElasticsearchPersistentProperty>, customConversionService: GenericConversionService?) : MappingElasticsearchConverter(mappingContext, customConversionService) {
private val conversionsNew = ElasticsearchCustomConversions(emptyList<Any>())
init {
setConversions(conversionsNew)
}
override fun <R : Any?> readValue(source: Any?, property: ElasticsearchPersistentProperty, targetType: TypeInformation<R>): R? {
if (source == null) {
return null
}
if (source is Collection<*>) {
return readCollectionValue(source, property, targetType) as R?;
}
return super.readValue(source, property, targetType);
}
private fun readCollectionValue(source: Collection<*>?, property: ElasticsearchPersistentProperty, targetType: TypeInformation<*>): Any? {
if (source == null) {
return null
}
val target = createCollectionForValue(targetType, source.size)
for (value in source) {
require(value != null) { "value must not be null" }
if (isSimpleType(value)) {
target.add(readSimpleValue(value, if (targetType.componentType != null) targetType.componentType!! else targetType))
} else {
if (value is MutableCollection<*>) {
target.add(readValue(value, property, property.typeInformation.actualType as TypeInformation<out Any>))
} else {
@Suppress("UNCHECKED_CAST")
target.add(readEntity(computeGenericValueTypeForRead(property, value), value as MutableMap<String, Any>?))
}
}
}
return target
}
private fun readSimpleValue(value: Any?, targetType: TypeInformation<*>): Any? {
val target = targetType.type
@Suppress("SENSELESS_COMPARISON")
if (value == null || target == null || ClassUtils.isAssignableValue(target, value)) {
return value
}
if (conversionsNew.hasCustomReadTarget(value.javaClass, target)) {
return conversionService.convert(value, target)
}
@Suppress("UNCHECKED_CAST")
return when {
Enum::class.java.isAssignableFrom(target) -> enumByName(target as Class<Enum<*>>, value.toString())
else -> conversionService.convert(value, target)
}
}
private fun enumByName(target: Class<Enum<*>>, name: String): Enum<*> {
val enumValue = target.enumConstants.find { it.name == name }
require(enumValue != null) { "no enum value found for name $name and targetClass $target" }
return enumValue
}
private fun createCollectionForValue(collectionTypeInformation: TypeInformation<*>, size: Int): MutableCollection<Any?> {
val collectionType = when {
collectionTypeInformation.isCollectionLike -> collectionTypeInformation.type
else -> MutableList::class.java
}
val componentType = when {
collectionTypeInformation.componentType != null -> collectionTypeInformation.componentType
else -> ClassTypeInformation.OBJECT
}
return when {
collectionTypeInformation.type.isArray -> ArrayList(size)
else -> CollectionFactory.createCollection(collectionType, componentType!!.type, size)
}
}
private fun computeGenericValueTypeForRead(property: ElasticsearchPersistentProperty, value: Any): ElasticsearchPersistentEntity<*> {
return when {
ClassTypeInformation.OBJECT == property.typeInformation.actualType -> mappingContext.getRequiredPersistentEntity(value.javaClass)
else -> mappingContext.getRequiredPersistentEntity(property.typeInformation.actualType!!)
}
}
private fun isSimpleType(value: Any): Boolean {
return isSimpleType(value.javaClass)
}
private fun isSimpleType(type: Class<*>): Boolean {
return conversionsNew.isSimpleType(type)
}
}
在此之后,一些存储库查询的问题在哪里得到了解决。请注意不要使用spring boot starter data elasticsearch
而是spring data elasticsearch:4.0.0。构建快照
。(这花了我一些时间)。
是的,代码很难看,但是spring data elasticsearch:4.0.0
发布后,您可以扔掉它。
更新
Spring Boot 2.3正在集成Spring-data-elasticsearch 4,因此它将开箱即用地支持ElasticSearch 7. x。它将很快发布,但您已经可以尝试了:
plugins {
id 'org.springframework.boot' version '2.3.0.RC1'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
我已经对它进行了积极的测试,我所有的测试场景都通过了,所以我肯定会推荐这种方式。对于因某些原因无法升级到2.3的用户,我将保留下面的答案。
旧的解决方法(以前的版本原始答案)
由于我们真的不知道Spring Data Elastic Search 4. x何时发布,我发布了我集成当前Spring Data Elastic Search 4. x和稳定Spring Boot 2.1.7的方法。如果您想使用Spring存储库和最新的弹性搜索,它可能是您的临时解决方案。
1) 在依赖项中强制使用最新的弹性搜索客户端(在我的例子中是build.gradle)
dependencies {
//Force spring-data to use the newest elastic-search client
//this should removed as soon as spring-data-elasticsearch:4.0.0 is released!
implementation('org.springframework.data:spring-data-elasticsearch:4.0.0.BUILD-SNAPSHOT') {
exclude group: 'org.elasticsearch'
exclude group: 'org.elasticsearch.plugin'
exclude group: 'org.elasticsearch.client'
}
implementation('org.elasticsearch:elasticsearch:7.3.0') { force = true }
implementation('org.elasticsearch.client:elasticsearch-rest-high-level-client:7.3.0') { force = true }
implementation('org.elasticsearch.client:elasticsearch-rest-client:7.3.0') { force = true }
}
2) 禁用Elastic Search自动配置和运行状况检查组件,因为它们变得不兼容(以后可能需要实施自己的运行状况检查)。
@SpringBootApplication(exclude = {ElasticsearchAutoConfiguration.class, ElasticSearchRestHealthIndicatorAutoConfiguration.class})
@EnableElasticsearchRepositories
public class SpringBootApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootApp.class, args);
}
}
3) 当我们禁用自动配置时,我们需要自己初始化ElasticsearchRestTemplate
。我们还需要提供定制的MappingElasticsearchConverter
,以避免类不兼容。
/**
* Manual configuration to support the newest ElasticSearch that is currently not supported by {@link org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration}.
*
* @author aleksanderlech
*/
@Configuration
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticSearchConfiguration {
@Primary
@Bean
public ElasticsearchRestTemplate elasticsearchTemplate(ElasticsearchProperties configuration) {
var nodes = Stream.of(configuration.getClusterNodes().split(",")).map(HttpHost::create).toArray(HttpHost[]::new);
var client = new RestHighLevelClient(RestClient.builder(nodes));
var converter = new CustomElasticSearchConverter(new SimpleElasticsearchMappingContext(), createConversionService());
return new ElasticsearchRestTemplate(client, converter, new DefaultResultMapper(converter));
}
private DefaultConversionService createConversionService() {
var conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToLocalDateConverter());
return conversionService;
}
}
CustomElasticSearch转换器:
/**
* Custom version of {@link MappingElasticsearchConverter} to support newest Spring Data Elasticsearch integration that supports ElasticSearch 7. Remove when Spring Data Elasticsearch 4.x is released.
*/
class CustomElasticSearchConverter extends MappingElasticsearchConverter {
private CustomConversions conversions = new ElasticsearchCustomConversions(Collections.emptyList());
CustomElasticSearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
super(mappingContext);
setConversions(conversions);
}
CustomElasticSearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, GenericConversionService conversionService) {
super(mappingContext, conversionService);
setConversions(conversions);
}
@Override
protected <R> R readValue(@Nullable Object source, ElasticsearchPersistentProperty property,
TypeInformation<R> targetType) {
if (source == null) {
return null;
}
if (source instanceof List) {
return readCollectionValue((List) source, property, targetType);
}
return super.readValue(source, property, targetType);
}
private Object readSimpleValue(@Nullable Object value, TypeInformation<?> targetType) {
Class<?> target = targetType.getType();
if (value == null || target == null || ClassUtils.isAssignableValue(target, value)) {
return value;
}
if (conversions.hasCustomReadTarget(value.getClass(), target)) {
return getConversionService().convert(value, target);
}
if (Enum.class.isAssignableFrom(target)) {
return Enum.valueOf((Class<Enum>) target, value.toString());
}
return getConversionService().convert(value, target);
}
private <R> R readCollectionValue(@Nullable List<?> source, ElasticsearchPersistentProperty property,
TypeInformation<R> targetType) {
if (source == null) {
return null;
}
Collection<Object> target = createCollectionForValue(targetType, source.size());
for (Object value : source) {
if (isSimpleType(value)) {
target.add(
readSimpleValue(value, targetType.getComponentType() != null ? targetType.getComponentType() : targetType));
} else {
if (value instanceof List) {
target.add(readValue(value, property, property.getTypeInformation().getActualType()));
} else {
target.add(readEntity(computeGenericValueTypeForRead(property, value), (Map) value));
}
}
}
return (R) target;
}
private Collection<Object> createCollectionForValue(TypeInformation<?> collectionTypeInformation, int size) {
Class<?> collectionType = collectionTypeInformation.isCollectionLike()//
? collectionTypeInformation.getType() //
: List.class;
TypeInformation<?> componentType = collectionTypeInformation.getComponentType() != null //
? collectionTypeInformation.getComponentType() //
: ClassTypeInformation.OBJECT;
return collectionTypeInformation.getType().isArray() //
? new ArrayList<>(size) //
: CollectionFactory.createCollection(collectionType, componentType.getType(), size);
}
private ElasticsearchPersistentEntity<?> computeGenericValueTypeForRead(ElasticsearchPersistentProperty property,
Object value) {
return ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType())
? getMappingContext().getRequiredPersistentEntity(value.getClass())
: getMappingContext().getRequiredPersistentEntity(property.getTypeInformation().getActualType());
}
private boolean isSimpleType(Object value) {
return isSimpleType(value.getClass());
}
private boolean isSimpleType(Class<?> type) {
return conversions.isSimpleType(type);
}
}
我使用springboot和jersey作为restful API。现在我想将swagger2集成到我的项目中,但它不起作用。当我运行我的应用程序并访问http://localhost:8080/swagger-ui.html.我得到了swagger网页,但没有显示api(见下图)。似乎swagger没有找到我的api类。 下面是我添加的依赖项。 以下是我的申请课程: 下面是我的jersey配置类
SpringBoot项目中parent中没有默认版本的依赖如何选择版本?类如mybatis-spring-boot-starter依赖,parent中是没有默认配置的。我想请问类似这种情况如何选择合适的依赖版本呢?我在mybatis官网也没有找到相关资料,依赖的jar包中也没有,我不喜欢看网友给的资料,我还是喜欢看官网的资料,大家都是怎么选择的呢?靠经验?靠百度? 尝试过百度和查看官网,想知道对于
就目前而言,虽然.NET Core3.1存在并有LTS,但我仍然生活在2.x的世界中。 下面的行来自 https://dotnet.microsoft.com/platform/support/policy/dotnet-core 因此。NET Core2.2就是EOL。但是。NET Core2.1是LTS。好吧... Microsoft.Extensions.HTTP https://www.n
目前,我的应用程序使用SpringMVC进行所有控制器映射。我正在尝试实现一个tinyMCE拼写检查,它包括一个Servlet,我不确定如何在不修改该文件本身的情况下正确集成该Servlet。我想避免修改,这样如果我们以后有新版本,我们就可以了。 Servlet看起来像...
问题内容: 有人知道将soapUI测试添加到我的CI版本的好方法吗? 问题答案: soapUI通过Maven或Ant提供测试自动化。在这里描述了Maven集成。 我在一个月前尝试过,但是在eviware存储库中遇到了一些奇怪的问题…因此,我现在通过Ant运行测试。您要做的是在soapUI bin目录中调用(或)脚本。您可以在此处找到可用的参数。 您必须在Hudson构建服务器上安装soapUI。然
问题内容: 我正在寻找有关symfony2中有关ajax的简单教程/示例,供初学者使用? 我有这些例子: city.php:http://pastebin.com/Qm8LS5kh ajax_req.js:http://pastebin.com/UqJMad24 index.html:http://pastebin.com/H1err4Yh 如何将它们放入Symfony2应用程序中? 问题答案: