easy-es-spring 关于spring的适配,多数据源待完成。。

This commit is contained in:
阿杰 2025-01-06 22:40:07 +08:00
parent d9eedb1b02
commit 21c1bd90c2
46 changed files with 3792 additions and 23 deletions

View File

@ -2,7 +2,7 @@ package org.dromara.easyes.starter.config;
import lombok.Data; import lombok.Data;
import org.dromara.easyes.common.enums.SchemaEnum; import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@ -9,7 +9,7 @@ import org.dromara.easyes.common.utils.TypeUtils;
import org.dromara.easyes.core.biz.EntityInfo; import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.cache.BaseCache; import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.proxy.EsMapperProxy; import org.dromara.easyes.core.proxy.EsMapperProxy;
import org.dromara.easyes.core.toolkit.EntityInfoHelper; import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.extension.context.Interceptor; import org.dromara.easyes.extension.context.Interceptor;

View File

@ -18,6 +18,10 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-annotation</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.elasticsearch.client</groupId> <groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId> <artifactId>elasticsearch-rest-high-level-client</artifactId>

View File

@ -18,6 +18,10 @@ public interface BaseEsConstants {
* 是否开启iKun模式 * 是否开启iKun模式
*/ */
String ENABLE_I_KUN_MODE = "easy-es.global-config.i-kun-mode"; String ENABLE_I_KUN_MODE = "easy-es.global-config.i-kun-mode";
/**
* 是否开启iKun模式
*/
String INDEX_MODE = "easy-es.global-config.process-index-mode";
/** /**
* 默认主键名称 * 默认主键名称
*/ */

View File

@ -1,5 +1,4 @@
package org.dromara.easyes.core.config; package org.dromara.easyes.common.property;
import lombok.Data; import lombok.Data;
import org.dromara.easyes.annotation.rely.FieldStrategy; import org.dromara.easyes.annotation.rely.FieldStrategy;

View File

@ -8,7 +8,7 @@ import lombok.Setter;
import org.dromara.easyes.annotation.IndexField; import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.rely.FieldStrategy; import org.dromara.easyes.annotation.rely.FieldStrategy;
import org.dromara.easyes.annotation.rely.FieldType; import org.dromara.easyes.annotation.rely.FieldType;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;

View File

@ -1,6 +1,6 @@
package org.dromara.easyes.core.cache; package org.dromara.easyes.core.cache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;

View File

@ -20,7 +20,7 @@ import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.core.biz.*; import org.dromara.easyes.core.biz.*;
import org.dromara.easyes.core.cache.BaseCache; import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.toolkit.EntityInfoHelper; import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.FieldUtils; import org.dromara.easyes.core.toolkit.FieldUtils;
import org.dromara.easyes.core.toolkit.IndexUtils; import org.dromara.easyes.core.toolkit.IndexUtils;

View File

@ -0,0 +1,25 @@
package org.dromara.easyes.core.service;
import org.elasticsearch.client.RestHighLevelClient;
/**
* 自动托管索引接口
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public interface AutoProcessIndexService {
/**
* 获取当前策略类型
*
* @return 策略类型
*/
Integer getStrategyType();
/**
* 异步处理索引
*
* @param entityClass 实体类
* @param client restHighLevelClient
*/
void processIndexAsync(Class<?> entityClass, RestHighLevelClient client);
}

View File

@ -14,7 +14,7 @@ import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.HighLightParam; import org.dromara.easyes.core.biz.HighLightParam;
import org.dromara.easyes.core.cache.BaseCache; import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;

View File

@ -5,7 +5,7 @@ import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.common.params.SFunction; import org.dromara.easyes.common.params.SFunction;
import org.dromara.easyes.common.utils.StringUtils; import org.dromara.easyes.common.utils.StringUtils;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;

View File

@ -12,7 +12,7 @@ import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.*; import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.core.biz.*; import org.dromara.easyes.core.biz.*;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;

View File

@ -19,10 +19,6 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-annotation</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.dromara.easy-es</groupId> <groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-common</artifactId> <artifactId>easy-es-common</artifactId>

View File

@ -26,6 +26,7 @@
<module>../easy-es-annotation</module> <module>../easy-es-annotation</module>
<module>../easy-es-common</module> <module>../easy-es-common</module>
<module>../easy-es-solon-plugin</module> <module>../easy-es-solon-plugin</module>
<module>../easy-es-spring</module>
</modules> </modules>
<properties> <properties>
@ -36,6 +37,7 @@
<fastjson.version>1.2.83</fastjson.version> <fastjson.version>1.2.83</fastjson.version>
<codec.version>1.13</codec.version> <codec.version>1.13</codec.version>
<spring-boot.version>2.6.10</spring-boot.version> <spring-boot.version>2.6.10</spring-boot.version>
<spring.version>5.3.22</spring.version>
<solon.version>3.0.5</solon.version> <solon.version>3.0.5</solon.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version> <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
</properties> </properties>
@ -105,10 +107,27 @@
<artifactId>solon</artifactId> <artifactId>solon</artifactId>
<version>${solon.version}</version> <version>${solon.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.noear</groupId> <groupId>org.springframework</groupId>
<artifactId>solon-serialization-fastjson</artifactId> <artifactId>spring-beans</artifactId>
<version>${solon.version}</version> <version>${spring.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@ -2,7 +2,7 @@ package org.dromara.easyes.solon.config;
import lombok.Data; import lombok.Data;
import org.dromara.easyes.common.enums.SchemaEnum; import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.noear.solon.annotation.Condition; import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration; import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject; import org.noear.solon.annotation.Inject;

View File

@ -10,7 +10,7 @@ import org.dromara.easyes.common.utils.TypeUtils;
import org.dromara.easyes.core.biz.EntityInfo; import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.cache.BaseCache; import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache; import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.config.GlobalConfig; import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.kernel.BaseEsMapper; import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.core.proxy.EsMapperProxy; import org.dromara.easyes.core.proxy.EsMapperProxy;
import org.dromara.easyes.core.toolkit.EntityInfoHelper; import org.dromara.easyes.core.toolkit.EntityInfoHelper;
@ -25,16 +25,12 @@ import org.noear.solon.Solon;
import org.noear.solon.core.AppContext; import org.noear.solon.core.AppContext;
import org.noear.solon.core.BeanBuilder; import org.noear.solon.core.BeanBuilder;
import org.noear.solon.core.BeanWrap; import org.noear.solon.core.BeanWrap;
import org.noear.solon.core.route.PathRule;
import org.noear.solon.core.util.ClassUtil; import org.noear.solon.core.util.ClassUtil;
import org.noear.solon.core.util.LogUtil;
import org.noear.solon.core.util.ScanUtil;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static org.dromara.easyes.common.constants.BaseEsConstants.*; import static org.dromara.easyes.common.constants.BaseEsConstants.*;

50
easy-es-spring/pom.xml Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-parent</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>easy-es-spring</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,125 @@
package org.dromara.easyes.spring;
import lombok.Setter;
import org.dromara.easyes.common.utils.RestHighLevelClientUtils;
import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.env.Environment;
import java.util.Arrays;
import java.util.Set;
/**
* 扫描指定路径下的所有接口
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
@Setter
private IndexStrategyFactory indexStrategyFactory;
@Setter
private RestHighLevelClientUtils restHighLevelClientUtils;
@Setter
private GlobalConfig globalConfig;
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
/**
* 配置扫描注册
* @param registry bean注册器
* @param environment 变量
* @author MoJie
*/
public ClassPathMapperScanner(BeanDefinitionRegistry registry, Environment environment) {
super(registry, false, environment);
}
public void registerFilters() {
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> {
// 跳过非ee的mapper,比如瞎几把写的接口,没有继承BaseEsMapper
String className = metadataReader.getClassMetadata().getClassName();
try {
Class<?> clazz = Class.forName(className);
return BaseEsMapper.class.isAssignableFrom(clazz);
} catch (ClassNotFoundException e) {
logger.debug("mapper not found" + e);
}
return true;
});
// exclude package-info.java
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No Easy-Es mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + beanClassName + "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
definition.setBeanClass(MapperFactoryBean.class);
// 属性注入
definition.getPropertyValues().add("globalConfig", this.globalConfig);
// 索引策略工厂注入
definition.getPropertyValues().add("indexStrategyFactory", this.indexStrategyFactory);
// easy-es client连接工具类
definition.getPropertyValues().add("restHighLevelClientUtils", this.restHighLevelClientUtils);
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn("Skipping MapperFactoryBean with name '" + beanName
+ "' and '" + beanDefinition.getBeanClassName() + "' mapperInterface"
+ ". Bean already defined with the same name!");
return false;
}
}
}

View File

@ -0,0 +1,128 @@
package org.dromara.easyes.spring;
import lombok.Setter;
import org.dromara.easyes.annotation.EsDS;
import org.dromara.easyes.annotation.Intercepts;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.common.utils.RestHighLevelClientUtils;
import org.dromara.easyes.common.utils.TypeUtils;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.proxy.EsMapperProxy;
import org.dromara.easyes.core.service.AutoProcessIndexService;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.extension.context.Interceptor;
import org.dromara.easyes.extension.context.InterceptorChain;
import org.dromara.easyes.extension.context.InterceptorChainHolder;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import static org.dromara.easyes.common.constants.BaseEsConstants.ZERO;
import static org.dromara.easyes.common.utils.RestHighLevelClientUtils.DEFAULT_DS;
/**
* 代理类
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class MapperFactoryBean<T> implements FactoryBean<T> {
private Class<T> mapperInterface;
@Autowired
private ApplicationContext applicationContext;
@Setter
private IndexStrategyFactory indexStrategyFactory;
@Setter
private GlobalConfig globalConfig;
@Setter
private RestHighLevelClientUtils restHighLevelClientUtils;
public MapperFactoryBean() {
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
EsMapperProxy<T> esMapperProxy = new EsMapperProxy<>(mapperInterface, new ConcurrentHashMap<>());
// 获取实体类
Class<?> entityClass = TypeUtils.getInterfaceT(mapperInterface, ZERO);
// 初始化缓存
GlobalConfigCache.setGlobalConfig(globalConfig);
//获取动态数据源 若未配置多数据源,则使用默认数据源
String restHighLevelClientId = Optional.ofNullable(mapperInterface.getAnnotation(EsDS.class)).map(EsDS::value).orElse(DEFAULT_DS);
RestHighLevelClient client = restHighLevelClientUtils.getClient(restHighLevelClientId);
BaseCache.initCache(mapperInterface, entityClass, client);
// 创建代理
T t = (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, esMapperProxy);
// 初始化拦截器链
InterceptorChain interceptorChain = this.initInterceptorChain();
// 异步处理索引创建/更新/数据迁移等
if (!ProcessIndexStrategyEnum.MANUAL.equals(globalConfig.getProcessIndexMode())) {
// 父子类型,仅针对父类型创建索引,子类型不创建索引
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
boolean isChild = entityInfo.isChild();
if (!isChild) {
AutoProcessIndexService autoProcessIndexService = indexStrategyFactory
.getByStrategyType(globalConfig.getProcessIndexMode().getStrategyType());
autoProcessIndexService.processIndexAsync(entityClass, client);
}
} else {
LogUtils.info("===> manual index mode activated");
}
return interceptorChain.pluginAll(t);
}
@Override
public Class<?> getObjectType() {
return this.mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
private InterceptorChain initInterceptorChain() {
InterceptorChainHolder interceptorChainHolder = InterceptorChainHolder.getInstance();
InterceptorChain interceptorChain = interceptorChainHolder.getInterceptorChain();
if (interceptorChain == null) {
synchronized (this) {
interceptorChainHolder.initInterceptorChain();
Map<String, Object> beansWithAnnotation = this.applicationContext.getBeansWithAnnotation(Intercepts.class);
beansWithAnnotation.forEach((key, val) -> {
if (val instanceof Interceptor) {
Interceptor interceptor = (Interceptor) val;
interceptorChainHolder.addInterceptor(interceptor);
}
});
}
}
return interceptorChainHolder.getInterceptorChain();
}
}

View File

@ -0,0 +1,315 @@
package org.dromara.easyes.spring;
import lombok.Setter;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.dromara.easyes.spring.property.EasyEsProperty;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyResourceConfigurer;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import javax.net.ssl.SSLContext;
import java.util.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
/**
* spring配置类扫描
* @author MoJie
* @since 2.0
*/
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
@Setter
private String basePackage;
@Setter
private IndexStrategyFactory indexStrategyFactory;
@Setter
private RestHighLevelClientUtils restHighLevelClientUtils;
private ApplicationContext applicationContext;
private String beanName;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
Boolean enable = getEnvironment().getProperty(ENABLE_PREFIX, Boolean.TYPE, true);
if (!enable) {
LogUtils.info("===> Easy-Es is not enabled");
return;
}
this.printBanner();
Map<String, PropertyResourceConfigurer> prcs = applicationContext
.getBeansOfType(PropertyResourceConfigurer.class, false, false);
// 如果spring动态配置上下文中存在那么到上下文对象中获取/比如在*.properties中配置了键值对
if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext) {
BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext) applicationContext).getBeanFactory()
.getBeanDefinition(beanName);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition(beanName, mapperScannerBean);
for (PropertyResourceConfigurer prc : prcs.values()) {
prc.postProcessBeanFactory(factory);
}
PropertyValues values = mapperScannerBean.getPropertyValues();
this.basePackage = getPropertyValue("basePackage", values);
}
// 取变量
this.basePackage = Optional.ofNullable(this.basePackage)
.map(getEnvironment()::resolvePlaceholders).orElse(null);
// 做扫包的操作了与注解扫包类似只不过这里是spring配置方式
// 在mybatis中配置了很多扫描拦截属性这里放到后面拓展
ClassPathMapperScanner scanner = new ClassPathMapperScanner(beanDefinitionRegistry, getEnvironment());
scanner.registerFilters();
// 索引策略工厂 -- 需要spring 注册bean xml/component 注解方式均可
scanner.setIndexStrategyFactory(this.indexStrategyFactory);
EasyEsProperty easyEsProperty = new EasyEsProperty(this.getEnvironment());
scanner.setGlobalConfig(easyEsProperty.getGlobalConfig());
// easy-es的连接对象注册 需要spring 注册bean xml/component 注解方式均可
if (this.restHighLevelClientUtils == null) {
RestHighLevelClientUtils restHighLevelClientUtils = new RestHighLevelClientUtils();
Map<String, EasyEsProperty> datasourceMap = easyEsProperty.getDatasource();
if (CollectionUtils.isEmpty(datasourceMap)) {
// 设置默认数据源,兼容不使用多数据源配置场景的老用户使用习惯
datasourceMap.put(RestHighLevelClientUtils.DEFAULT_DS, easyEsProperty);
}
for (String key : datasourceMap.keySet()) {
EasyEsProperty easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, restHighLevelClient(easyEsConfigProperties));
}
this.restHighLevelClientUtils = restHighLevelClientUtils;
}
scanner.setRestHighLevelClientUtils(this.restHighLevelClientUtils);
scanner.doScan(this.basePackage);
}
private String getPropertyValue(String propertyName, PropertyValues values) {
PropertyValue property = values.getPropertyValue(propertyName);
if (property == null) {
return null;
}
Object value = property.getValue();
if (value == null) {
return null;
}
if (value instanceof String) {
return value.toString();
}
if (value instanceof TypedStringValue) {
return ((TypedStringValue) value).getValue();
}
return null;
}
private Environment getEnvironment() {
return this.applicationContext.getEnvironment();
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
/**
* bean 注册完成后校验属性是否注入
* @author MoJie
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.basePackage, "Property 'basePackage' is required. mapper扫包路径为必填。");
Assert.notNull(this.indexStrategyFactory, "Property 'indexStrategyFactory' is required. " +
"请注册索引策略工厂实现。");
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 打印banner
* @author MoJie
*/
private void printBanner() {
//打印banner @author dazer007
Boolean banner = getEnvironment().getProperty(ENABLE_BANNER, Boolean.class, true);
if (banner) {
Boolean iKunMode = getEnvironment().getProperty(ENABLE_I_KUN_MODE, Boolean.TYPE, false);
String versionStr = EEVersionUtils.getJarVersion(this.getClass());
String wechatStr = ":: wechat :: 252645816, add and become muscle man! >";
if (iKunMode) {
System.out.println(" 鸡你太美\n" +
" 鸡你实在太美\n" +
" 鸡你是太美\n" +
" 鸡你太美\n" +
" 实在是太美鸡你\n" +
" 鸡你 实在是太美鸡你 美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 鸡你实在是美太美 美蓝球球球\n" +
"鸡 鸡 鸡你实在是太美 篮球篮球球球球\n" +
" 鸡 鸡你太美裆鸡太啊 球球蓝篮球球\n" +
" 鸡你太美裆裆鸡美 球球球\n" +
" 鸡你裆小 j 鸡太美\n" +
" 鸡太美 鸡太美\n" +
" 鸡美 鸡美\n" +
" 鸡美 鸡美\n" +
" 鸡美 鸡美\n" +
" 鸡太 鸡太\n" +
" 鸡 脚 鸡脚\n" +
" 皮 鞋 皮鞋金猴\n" +
" 金光 金光 大道\n" +
" 大道\n" +
" 鸡神保佑 永不宕机 永无BUG");
wechatStr = ":: wechat :: 252645816, add and join ikun(小黑子) group! >";
} else {
System.out.println("\n" +
"___ _ _ ___\n" +
" | __| __ _ ___ | || | ___ | __| ___\n" +
" | _| / _` | (_-< \\_, | |___| | _| (_-<\n" +
" |___| \\__,_| /__/_ _|__/ _____ |___| /__/_\n" +
"_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_| \"\"\"\"|_| |_|\"\"\"\"\"|_|\"\"\"\"\"|\n" +
"\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\n" +
"----------------------------------------------------------->"
);
}
// 版本长度并不固定,比如beta版,所以需要特殊处理
int width = 43;
int blank = width - versionStr.length();
StringBuilder sb = new StringBuilder();
sb.append(":: version :: ")
.append(versionStr);
for (int i = 0; i < blank; i++) {
sb.append(" ");
}
sb.append(">");
if (iKunMode) {
System.out.println("----------------------------------------------------------->");
}
System.out.println(":: project :: Easy-Es >");
System.out.println(sb);
System.out.println(":: home :: https://easy-es.cn/ >");
System.out.println(":: community :: https://dromara.org/ >");
System.out.println(wechatStr);
System.out.println("----------------------------------------------------------->");
}
}
private Map<String, Object> getDatasource() {
String dynamic = this.applicationContext.getEnvironment().getRequiredProperty("easy-es.dynamic");
Properties properties = new Properties();
Map<String, Object> map = new HashMap<>();
try {
properties.load(new java.io.StringReader(dynamic));
properties.forEach((key, value) -> map.put(key.toString(), value.toString()));
} catch (Exception e) {
// Handle exception
}
return map;
}
private static RestHighLevelClient restHighLevelClient(EasyEsProperty easyEsConfigProperties) {
// 处理地址
String address = easyEsConfigProperties.getAddress();
if (StringUtils.isEmpty(address)) {
throw ExceptionUtils.eee("please config the es address");
}
if (!address.contains(COLON)) {
throw ExceptionUtils.eee("the address must contains port and separate by ':'");
}
String schema = StringUtils.isEmpty(easyEsConfigProperties.getSchema())
? DEFAULT_SCHEMA : easyEsConfigProperties.getSchema();
List<HttpHost> hostList = new ArrayList<>();
Arrays.stream(easyEsConfigProperties.getAddress().split(COMMA))
.forEach(item -> hostList.add(new HttpHost(item.split(COLON)[0],
Integer.parseInt(item.split(COLON)[1]), schema)));
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
// 设置心跳时间,最大连接数,最大连接路由
Optional.ofNullable(easyEsConfigProperties.getKeepAliveMillis()).ifPresent(p -> httpClientBuilder.setKeepAliveStrategy((response, context) -> p));
Optional.ofNullable(easyEsConfigProperties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
Optional.ofNullable(easyEsConfigProperties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
// 设置账号密码
String username = easyEsConfigProperties.getUsername();
String password = easyEsConfigProperties.getPassword();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// https ssl ignore
if (SchemaEnum.https.name().equals(schema)) {
try {
// 信任所有
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
httpClientBuilder.disableAuthCaching();
httpClientBuilder.setSSLStrategy(sessionStrategy);
} catch (Exception e) {
LogUtils.error("restHighLevelClient build SSLContext exception: %s", e.getMessage());
e.printStackTrace();
throw ExceptionUtils.eee(e);
}
}
return httpClientBuilder;
});
// 设置超时时间之类的
builder.setRequestConfigCallback(requestConfigBuilder -> {
Optional.ofNullable(easyEsConfigProperties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
Optional.ofNullable(easyEsConfigProperties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
Optional.ofNullable(easyEsConfigProperties.getConnectionRequestTimeout())
.ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
return requestConfigBuilder;
});
return new RestHighLevelClient(builder);
}
}

View File

@ -0,0 +1,101 @@
package org.dromara.easyes.spring;
import org.dromara.easyes.common.utils.EEVersionUtils;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.spring.annotation.EsMapperScan;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
/**
* 注册bean
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class MapperScannerRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
private static final String BASE_PACKAGE = "basePackage";
private static final String INDEX_STRATEGY_FACTORY = "indexStrategyFactory";
private static final String REST_HIGH_LEVEL_CLIENT_UTILS = "restHighLevelClientUtils";
private static final String REST_HIGH_LEVEL_CLIENT_CONFIGURATION = "restHighLevelClientConfiguration";
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EsMapperScan.class.getName()));
// 默认已注解标记为主如果没有则尝试寻找easy-es配置 scan
if (mapperScanAttrs != null) {
List<String> basePackages = Arrays.stream(mapperScanAttrs.getStringArray("value"))
.filter(StringUtils::hasText).collect(Collectors.toList());
// 注册bean
registerBeanDefinitions(registry, generateBaseBeanName(importingClassMetadata, 0),
StringUtils.toStringArray(basePackages));
}
}
/**
* 通过BeanDefinition注册bean在bean注册前处理interface中bean参数问题interface与普通bean不同
* 使用了jdk动态代理需要确定注册的实际interface class就需要通过BeanDefinition来追加属性
* 当前使用到了spring的构造
* @param registry spring bean扫码注册器
* @param basePackages 扫码的包
*/
void registerBeanDefinitions(BeanDefinitionRegistry registry, String beanName, String... basePackages) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue(BASE_PACKAGE, String.join(",", basePackages));
if (registry.containsBeanDefinition(INDEX_STRATEGY_FACTORY)) {
builder.addPropertyValue(INDEX_STRATEGY_FACTORY, registry.getBeanDefinition(INDEX_STRATEGY_FACTORY));
}
// 如果自行注册了restHighLevelClientUtils那么就添加bean属性
if (registry.containsBeanDefinition(REST_HIGH_LEVEL_CLIENT_UTILS)) {
builder.addPropertyValue(REST_HIGH_LEVEL_CLIENT_UTILS, registry
.getBeanDefinition(REST_HIGH_LEVEL_CLIENT_UTILS));
} else {
// 没有注册restHighLevelClientUtils那么尝试寻找easy-es-spring的restHighLevelClientConfiguration
if (registry.containsBeanDefinition(REST_HIGH_LEVEL_CLIENT_CONFIGURATION)) {
builder.addPropertyValue(REST_HIGH_LEVEL_CLIENT_UTILS, registry
.getBeanDefinition(REST_HIGH_LEVEL_CLIENT_CONFIGURATION));
}
}
// for spring-native
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
return importingClassMetadata.getClassName() + "#" + MapperScannerRegister.class.getSimpleName() + "#" + index;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}

View File

@ -0,0 +1,19 @@
package org.dromara.easyes.spring.annotation;
import org.dromara.easyes.spring.MapperScannerRegister;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 全局Mapper扫描注解
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MapperScannerRegister.class)
public @interface EsMapperScan {
String[] value();
}

View File

@ -0,0 +1,60 @@
package org.dromara.easyes.spring.factory;
import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.Assert;
import org.dromara.easyes.common.utils.ExceptionUtils;
import org.dromara.easyes.core.service.AutoProcessIndexService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* 自动托管索引策略工厂
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public class IndexStrategyFactory implements ApplicationContextAware, InitializingBean {
/**
* 预估初始策略工厂容量
*/
private static final Integer DEFAULT_SIZE = 4;
/**
* spring上下文
*/
private ApplicationContext applicationContext;
/**
* 策略容器
*/
private static final Map<Integer, AutoProcessIndexService> SERVICE_MAP = new HashMap<>(DEFAULT_SIZE);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
Map<String, AutoProcessIndexService> beansOfType = this.applicationContext
.getBeansOfType(AutoProcessIndexService.class);
Assert.isTrue(beansOfType.isEmpty(), "AutoProcessIndexService must have implementation. " +
"AutoProcessIndexService接口必须要有索引策略实现。");
// 是否开启自动托管模式,默认开启
ProcessIndexStrategyEnum strategy = this.applicationContext.getEnvironment()
.getProperty(BaseEsConstants.INDEX_MODE, ProcessIndexStrategyEnum.class, ProcessIndexStrategyEnum.MANUAL);
if (!ProcessIndexStrategyEnum.MANUAL.equals(strategy)) {
// 将bean注册进工厂
beansOfType.values().forEach(v -> SERVICE_MAP.putIfAbsent(v.getStrategyType(), v));
}
}
public AutoProcessIndexService getByStrategyType(Integer strategyType) {
return Optional.ofNullable(SERVICE_MAP.get(strategyType))
.orElseThrow(() -> ExceptionUtils.eee("no such service strategyType:{}", strategyType));
}
}

View File

@ -0,0 +1,76 @@
package org.dromara.easyes.spring.index;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.core.biz.CreateIndexParam;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.EsIndexInfo;
import org.dromara.easyes.core.service.AutoProcessIndexService;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.IndexUtils;
import org.elasticsearch.client.RestHighLevelClient;
/**
* 自动非平滑托管索引实现类, 重建索引时原索引数据会被删除
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public class AutoProcessIndexNotSmoothlyServiceImpl implements AutoProcessIndexService {
@Override
public Integer getStrategyType() {
return ProcessIndexStrategyEnum.NOT_SMOOTHLY.getStrategyType();
}
@Override
public void processIndexAsync(Class<?> entityClass, RestHighLevelClient client) {
LogUtils.info("===> Not smoothly process index mode activated");
IndexUtils.supplyAsync(this::process, entityClass, client);
}
private boolean process(Class<?> entityClass, RestHighLevelClient client) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
// 是否存在索引
boolean existsIndex = IndexUtils.existsIndexWithRetry(entityInfo, client);
if (existsIndex) {
// 更新
LogUtils.info("===> Index exists, automatically updating index by easy-es...");
return doUpdateIndex(entityInfo, entityClass, client);
} else {
// 新建
LogUtils.info("===> Index not exists, automatically creating index by easy-es...");
return doCreateIndex(entityInfo, entityClass, client);
}
}
private boolean doUpdateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 获取索引信息
EsIndexInfo esIndexInfo = IndexUtils.getIndexInfo(client, entityInfo.getRetrySuccessIndexName());
// 索引是否有变化 若有则直接删除旧索引,创建新索引 若无则直接返回托管成功
boolean isIndexNeedChange = IndexUtils.isIndexNeedChange(esIndexInfo, entityInfo, clazz);
if (!isIndexNeedChange) {
LogUtils.info("===> index has nothing changed");
entityInfo.setIndexName(entityInfo.getRetrySuccessIndexName());
return Boolean.TRUE;
}
// 直接删除旧索引
IndexUtils.deleteIndex(client, entityInfo.getRetrySuccessIndexName());
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
private boolean doCreateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
}

View File

@ -0,0 +1,127 @@
package org.dromara.easyes.spring.index;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.core.biz.CreateIndexParam;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.EsIndexInfo;
import org.dromara.easyes.core.service.AutoProcessIndexService;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.IndexUtils;
import org.elasticsearch.client.RestHighLevelClient;
import static org.dromara.easyes.common.constants.BaseEsConstants.S1_SUFFIX;
import static org.dromara.easyes.common.constants.BaseEsConstants.SO_SUFFIX;
/**
* 自动平滑托管索引实现类,本框架默认模式,过程零停机,数据会自动转移至新索引
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public class AutoProcessIndexSmoothlyServiceImpl implements AutoProcessIndexService {
@Override
public Integer getStrategyType() {
return ProcessIndexStrategyEnum.SMOOTHLY.getStrategyType();
}
@Override
public void processIndexAsync(Class<?> entityClass, RestHighLevelClient client) {
LogUtils.info("===> Smoothly process index mode activated");
IndexUtils.supplyAsync(this::process, entityClass, client);
}
private synchronized boolean process(Class<?> entityClass, RestHighLevelClient client) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
// 索引是否已存在
boolean existsIndex = IndexUtils.existsIndexWithRetryAndSetActiveIndex(entityInfo, client);
if (existsIndex) {
// 更新
LogUtils.info("===> Index exists, automatically updating index by easy-es...");
return doUpdateIndex(entityInfo, entityClass, client);
} else {
// 新建
LogUtils.info("===> Index not exists, automatically creating index by easy-es...");
return doCreateIndex(entityInfo, entityClass, client);
}
}
private boolean doUpdateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 获取索引信息
EsIndexInfo esIndexInfo = IndexUtils.getIndexInfo(client, entityInfo.getIndexName());
// 是否存在默认别名,若无则给添加
if (!esIndexInfo.getHasDefaultAlias()) {
IndexUtils.addDefaultAlias(client, entityInfo.getIndexName());
}
// 索引是否有变化 若有则创建新索引并无感迁移, 若无则直接返回托管成功
boolean isIndexNeedChange = IndexUtils.isIndexNeedChange(esIndexInfo, entityInfo, clazz);
if (!isIndexNeedChange) {
LogUtils.info("===> index has nothing changed");
return Boolean.TRUE;
}
// 创建新索引
String releaseIndexName = generateReleaseIndexName(entityInfo.getIndexName());
entityInfo.setReleaseIndexName(releaseIndexName);
boolean isCreateIndexSuccess = doCreateIndex(entityInfo, clazz, client);
if (!isCreateIndexSuccess) {
LogUtils.error("create release index failed", "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 迁移数据至新创建的索引
boolean isDataMigrationSuccess = doDataMigration(entityInfo.getIndexName(), releaseIndexName, entityInfo.getMaxResultWindow(), client);
if (!isDataMigrationSuccess) {
LogUtils.error("migrate data failed", "oldIndex:" + entityInfo.getIndexName(), "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 原子操作 切换别名:将默认别名关联至新索引,并将旧索引的默认别名移除
boolean isChangeAliasSuccess = IndexUtils.changeAliasAtomic(client, entityInfo.getIndexName(), releaseIndexName);
if (!isChangeAliasSuccess) {
LogUtils.error("change alias atomically failed", "oldIndex:" + entityInfo.getIndexName(), "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 删除旧索引
boolean isDeletedIndexSuccess = IndexUtils.deleteIndex(client, entityInfo.getIndexName());
if (!isDeletedIndexSuccess) {
LogUtils.error("delete old index failed", "oldIndex:" + entityInfo.getIndexName());
return Boolean.FALSE;
}
// 用最新索引覆盖缓存中的老索引
entityInfo.setIndexName(releaseIndexName);
// 将新索引名称记录至ee-distribute-lock索引中,以便在分布式环境下其它机器能够感知到
IndexUtils.saveReleaseIndex(releaseIndexName, client);
// done.
return Boolean.TRUE;
}
private String generateReleaseIndexName(String oldIndexName) {
if (oldIndexName.endsWith(SO_SUFFIX)) {
return oldIndexName.split(SO_SUFFIX)[0] + S1_SUFFIX;
} else if (oldIndexName.endsWith(S1_SUFFIX)) {
return oldIndexName.split(S1_SUFFIX)[0] + SO_SUFFIX;
} else {
return oldIndexName + SO_SUFFIX;
}
}
private boolean doDataMigration(String oldIndexName, String releaseIndexName, Integer maxResultWindow, RestHighLevelClient client) {
return IndexUtils.reindex(client, oldIndexName, releaseIndexName, maxResultWindow);
}
private boolean doCreateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
}

View File

@ -0,0 +1,138 @@
package org.dromara.easyes.spring.property;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.dromara.easyes.annotation.rely.FieldStrategy;
import org.dromara.easyes.annotation.rely.IdType;
import org.dromara.easyes.annotation.rely.RefreshPolicy;
import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.common.utils.StringUtils;
import org.springframework.core.env.Environment;
import java.util.HashMap;
import java.util.Map;
import static org.dromara.easyes.common.constants.BaseEsConstants.EMPTY_STR;
/**
* easy-es基础配置项 考虑到spring的场景有些参数不是必须配置
* 基本类型就会出现默认值的情况 所以为了要有null值出现这里采用包装类型
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Data
public class EasyEsProperty {
/**
* 是否开启easy-es 默认开启
*/
private Boolean enable;
/**
* 是否开启easy-es LOGO BANNER的打印
*/
private Boolean banner;
/**
* es client address es客户端地址
*/
private String address;
/**
* schema 模式
*/
private String schema;
/**
* username of es 用户名,可缺省
*/
private String username;
/**
* password of es 密码,可缺省
*/
private String password;
/**
* maxConnectTotal 最大连接数
*/
private Integer maxConnTotal;
/**
* maxConnectPerRoute 最大连接路由数
*/
private Integer maxConnPerRoute;
/**
* connectTimeout timeUnit:millis 连接超时时间 单位毫秒
*/
private Integer connectTimeout;
/**
* socketTimeout timeUnit:millis 通讯超时时间 单位毫秒 默认10分钟 以免小白踩坑平滑模式下数据量过大迁移超时失败
*/
private Integer socketTimeout;
/***
* 保持心跳时间 timeUnit:millis 单位毫秒 默认30秒 防止小白白出现服务首次调用不成时不知所措
*/
private Integer keepAliveMillis;
/**
* connectionRequestTimeout timeUnit:millis 连接请求超时时间 单位毫秒
*/
private Integer connectionRequestTimeout;
/**
* global config 全局配置
*/
private GlobalConfig globalConfig;
/**
* 配置多动态数据源key datasource id
*/
private Map<String, EasyEsProperty> datasource = new HashMap<>();
public EasyEsProperty(Environment environment) {
this.setEnable(environment.getProperty(BaseEsConstants.ENABLE_PREFIX, Boolean.class, true));
this.setBanner(environment.getProperty(BaseEsConstants.ENABLE_BANNER, Boolean.class, true));
this.setAddress(environment.getProperty("easy-es.address", "127.0.0.1:9200"));
this.setSchema(environment.getProperty("easy-es.schema", SchemaEnum.http.name()));
this.setUsername(environment.getProperty("easy-es.username"));
this.setPassword(environment.getProperty("easy-es.password"));
this.setMaxConnTotal(environment.getProperty("easy-es.max-conn-total", Integer.class));
this.setMaxConnPerRoute(environment.getProperty("easy-es.max-conn-per-route", Integer.class));
this.setConnectTimeout(environment.getProperty("easy-es.connect-timeout", Integer.class));
this.setSocketTimeout(environment.getProperty("easy-es.socket-timeout", Integer.class, 600000));
this.setKeepAliveMillis(environment.getProperty("easy-es.keep-alive-millis", Integer.class, 30000));
this.setConnectionRequestTimeout(environment.getProperty("easy-es.connection-request-timeout", Integer.class));
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setPrintDsl(environment.getProperty("easy-es.global-config.print-dsl", Boolean.class, true));
globalConfig.setIKunMode(environment.getProperty("easy-es.global-config.i-kun-mode", Boolean.class, false));
globalConfig.setProcessIndexMode(environment.getProperty("easy-es.global-config.process-index-mode",
ProcessIndexStrategyEnum.class, ProcessIndexStrategyEnum.MANUAL));
globalConfig.setDistributed(environment.getProperty("easy-es.global-config.distributed", Boolean.class, true));
globalConfig.setReindexTimeOutHours(environment.getProperty("easy-es.global-config.reindex-time-out-hours",
Integer.class, 72));
globalConfig.setAsyncProcessIndexBlocking(environment.getProperty("easy-es.global-config.async-process-index-blocking",
Boolean.class, true));
globalConfig.setActiveReleaseIndexMaxRetry(environment.getProperty("easy-es.global-config.active-release-index-max-retry",
Integer.class, 4320));
globalConfig.setActiveReleaseIndexFixedDelay(environment.getProperty("easy-es.global-config.active-release-index-fixed-delay",
Integer.class, 60));
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setIndexPrefix(environment.getProperty("easy-es.global-config.db-config.index-prefix", EMPTY_STR));
dbConfig.setMapUnderscoreToCamelCase(environment.getProperty("easy-es.global-config.db-config.map-underscore-to-camel-case",
Boolean.class, false));
dbConfig.setIdType(environment.getProperty("easy-es.global-config.db-config.id-type", IdType.class, IdType.NONE));
dbConfig.setFieldStrategy(environment.getProperty("easy-es.global-config.db-config.field-strategy",
FieldStrategy.class, FieldStrategy.NOT_NULL));
dbConfig.setEnableTrackTotalHits(environment.getProperty("easy-es.global-config.db-config.enable-track-total-hits",
Boolean.class, true));
dbConfig.setRefreshPolicy(environment.getProperty("easy-es.global-config.db-config.refresh-policy",
RefreshPolicy.class, RefreshPolicy.NONE));
dbConfig.setBatchUpdateThreshold(environment.getProperty("easy-es.global-config.db-config.batch-update-threshold",
Integer.class, 10000));
dbConfig.setSmartAddKeywordSuffix(environment.getProperty("easy-es.global-config.db-config.smart-add-keyword-suffix",
Boolean.class, true));
globalConfig.setDbConfig(dbConfig);
this.setGlobalConfig(globalConfig);
// 设置多数据源
}
public EasyEsProperty() {
}
}

View File

@ -0,0 +1,16 @@
package org.dromara.easyes.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动类
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@SpringBootApplication
public class TestEasyEsApplication {
public static void main(String[] args) {
SpringApplication.run(TestEasyEsApplication.class, args);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
package org.dromara.easyes.test.config;
import org.dromara.easyes.spring.annotation.EsMapperScan;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author MoJie
* @since 2.0
*/
//@Configuration
//@EsMapperScan("org.dromara.easyes.test.mapper")
public class TestConfig {
@Bean
public IndexStrategyFactory indexStrategyFactory() {
return new IndexStrategyFactory();
}
}

View File

@ -0,0 +1,27 @@
package org.dromara.easyes.test.entity;
import lombok.Data;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.IndexId;
import org.dromara.easyes.annotation.rely.FieldType;
/**
* 作者 数据模型 Document的子文档,Document是其父文档
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
@Data
public class Author {
/**
* 作者id
*/
@IndexId
private String authorId;
/**
* 作者姓名
*/
@IndexField(fieldType = FieldType.KEYWORD)
private String authorName;
}

View File

@ -0,0 +1,25 @@
package org.dromara.easyes.test.entity;
import lombok.Data;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.rely.FieldType;
/**
* es 评论 数据模型 Document的子文档,Document是其父文档
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Data
public class Comment {
/**
* 评论id
*/
private String id;
/**
* 评论内容
*/
@IndexField(fieldType = FieldType.KEYWORD)
private String commentContent;
}

View File

@ -0,0 +1,27 @@
package org.dromara.easyes.test.entity;
import lombok.Data;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.IndexId;
import org.dromara.easyes.annotation.rely.FieldType;
/**
* 联系方式 数据模型 Author的子文档,Author是其父文档,Document是其爷文档
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
@Data
public class Contact {
/**
* 联系人id
*/
@IndexId
private String contactId;
/**
* 地址
*/
@IndexField(fieldType = FieldType.TEXT)
private String address;
}

View File

@ -0,0 +1,157 @@
package org.dromara.easyes.test.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.easyes.annotation.*;
import org.dromara.easyes.annotation.rely.*;
import org.dromara.easyes.test.settings.MySettingsProvider;
import java.math.BigDecimal;
import java.util.List;
/**
* es 数据模型 其中Join父子类型结构如下所示
* <pre>
* Document
* / \
* Comment Author
* \
* Contact
* </pre>
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Data
@Accessors(chain = true)
@Settings(shardsNum = 3, replicasNum = 2, settingsProvider = MySettingsProvider.class)
@IndexName(value = "easyes_document", keepGlobalPrefix = true, refreshPolicy = RefreshPolicy.IMMEDIATE)
@Join(nodes = {@Node(parentClass = Document.class, childClasses = {Author.class, Comment.class}), @Node(parentClass = Author.class, childClasses = Contact.class)})
public class Document {
/**
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
* 如果你想自定义es中的id为你提供的id,比如MySQL中的id,请将注解中的type指定为customize或直接在全局配置文件中指定,如此id便支持任意数据类型)
*/
@IndexId(type = IdType.CUSTOMIZE)
private String esId;
/**
* 文档标题,不指定类型默认被创建为keyword类型,可进行精确查询
*/
private String title;
/**
* 副标题
*/
private String subTitle;
/**
* 文档内容,指定了类型及存储/查询分词器
*/
@HighLight(mappingField = "highlightContent", fragmentSize = 10, numberOfFragments = 2, requireFieldMatch = false, preTag = "<em>", postTag = "</em>")
@IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_SMART)
private String content;
/**
* 作者 @TableField注解,并指明strategy = FieldStrategy.NOT_EMPTY 表示更新的时候的策略为 创建者不为空字符串时才更新
*/
@IndexField(strategy = FieldStrategy.NOT_EMPTY, fieldType = FieldType.KEYWORD_TEXT, analyzer = Analyzer.IK_SMART)
private String creator;
/**
* 可以聚合的text类型,字段名字随便取,注解中指定fieldData=true后text类型也可以支持聚合
*/
@IndexField(fieldType = FieldType.TEXT, fieldData = true)
private String filedData;
/**
* ip字段
*/
@IndexField(fieldType = FieldType.IP)
private String ipAddress;
/**
* 创建时间
*/
@IndexField(fieldType = FieldType.DATE, dateFormat = "yyyy-MM-dd HH:mm:ss")
private String gmtCreate;
/**
* es中实际不存在的字段,但模型中加了,为了不和es映射,可以在此类型字段上加上 注解@TableField,并指明exist=false
*/
@IndexField(exist = false)
private String notExistsField;
/**
* 地理位置经纬度坐标 例如: "40.13933715136454,116.63441990026217"
*/
@IndexField(fieldType = FieldType.GEO_POINT)
private String location;
/**
* 图形(例如圆心,矩形)
*/
@IndexField(fieldType = FieldType.GEO_SHAPE)
private String geoLocation;
/**
* 自定义字段名称
*/
@HighLight(preTag = "<nb>", postTag = "</nb>")
@IndexField(value = "wu-la", fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_SMART)
private String customField;
/**
* 忽略大小写字段此字段的值用eq查询(termQuery)不区分大小写值得注意的是es中keyword类型字段才支持忽略大小写
*/
@IndexField(fieldType = FieldType.KEYWORD, ignoreCase = true)
private String caseTest;
/**
* 高亮返回值被映射的字段
*/
private String highlightContent;
/**
* 文档点赞数
*/
private Integer starNum;
/**
* 此字段存null值,测试isNull时用
*/
private String nullField;
/**
* 嵌套类型 注意,务必像下面示例一样指定类型为nested及其nested class,否则会导致框架无法正常运行
*/
@IndexField(fieldType = FieldType.NESTED, nestedClass = User.class)
private List<User> users;
/**
* es返回的得分字段,字段名字随便取,只要加了@Score注解即可
*/
@Score(decimalPlaces = 2)
private Float score;
/**
* es返回的距离,字段名字随便取,距离单位以用户在序器中指定的为准,不指定es默认为:
*/
@Distance(decimalPlaces = 1)
private Double distance;
/**
* es返回的距离2,有N个排序器就有N个排序返回的距离 参考cn.easyes.test.all.AllTest#testOrderByDistanceMulti
*/
@Distance(decimalPlaces = 2)
private Double distance2;
/**
* 浮点数,可指定缩放因子,不指定默认值为100
*/
@IndexField(fieldType = FieldType.SCALED_FLOAT, scalingFactor = 101)
private BigDecimal bigNum;
/**
* 复合字段,此注解和SpringData中的MultiField用法类似 适用于对同一个字段通过多种分词器检索的场景
*/
@HighLight
@MultiIndexField(mainIndexField = @IndexField(fieldType = FieldType.KEYWORD),
otherIndexFields = {@InnerIndexField(suffix = "zh", fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART),
@InnerIndexField(suffix = "pinyin", fieldType = FieldType.TEXT, analyzer = Analyzer.PINYIN)})
private String multiField;
/**
* 英文名
*/
private String english;
/**
* 稠密向量类型dims 非负 最大为2048
*/
@IndexField(fieldType = FieldType.DENSE_VECTOR, dims = 3)
private double[] vector;
}

View File

@ -0,0 +1,50 @@
package org.dromara.easyes.test.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.easyes.annotation.HighLight;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.InnerIndexField;
import org.dromara.easyes.annotation.MultiIndexField;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldType;
/**
* 问答
*
* @ProductName: Hundsun HEP
* @ProjectName: easy-es
* @Package: com.xpc.easyes.sample.entity
* @Description: note
* @Author: xingpc37977
* @Date: 2022/5/12 17:18
* @UpdateUser: xingpc37977
* @UpdateDate: 2022/5/12 17:18
* @UpdateRemark: The modified content
* @Version: 1.0
* <p>
* Copyright © 2022 Hundsun Technologies Inc. All Rights Reserved
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Faq {
/**
* 问题 高亮内容直接覆盖在原字段值上进行返回,故不需要指定高亮注解中的mappingField
*/
@HighLight
@MultiIndexField(mainIndexField = @IndexField,
otherIndexFields = {
@InnerIndexField(suffix = "ik", fieldType = FieldType.TEXT, analyzer = Analyzer.IK_MAX_WORD),
@InnerIndexField(suffix = "py", fieldType = FieldType.TEXT, analyzer = Analyzer.PINYIN)
})
private String faqName;
/**
* 答案
*/
@IndexField(value = "answer")
private String faqAnswer;
}

View File

@ -0,0 +1,60 @@
package org.dromara.easyes.test.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.easyes.annotation.HighLight;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.InnerIndexField;
import org.dromara.easyes.annotation.MultiIndexField;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldType;
import org.dromara.easyes.test.entity.Faq;
import java.util.Set;
/**
* es 嵌套类型
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Data
@NoArgsConstructor
public class User {
/**
* 用户名
*/
@HighLight(mappingField = "highlightUsername")
@MultiIndexField(mainIndexField = @IndexField("user_name"),
otherIndexFields = {
@InnerIndexField(suffix = "ik", fieldType = FieldType.TEXT, analyzer = Analyzer.IK_MAX_WORD),
@InnerIndexField(suffix = "py", fieldType = FieldType.TEXT, analyzer = Analyzer.PINYIN)
})
private String username;
/**
* 年龄
*/
@IndexField(fieldType = FieldType.INTEGER)
private Integer age;
/**
* 密码
*/
@IndexField(fieldType = FieldType.KEYWORD)
private String password;
/**
* 多级嵌套
*/
@IndexField(fieldType = FieldType.NESTED, nestedClass = Faq.class)
private Set<Faq> faqs;
/**
* 高亮显示的内容
*/
private String highlightUsername;
public User(String username, Integer age, String password, Set<Faq> faqs) {
this.username = username;
this.age = age;
this.password = password;
this.faqs = faqs;
}
}

View File

@ -0,0 +1,37 @@
package org.dromara.easyes.test.generated;
import lombok.Data;
import org.dromara.easyes.annotation.IndexName;
import org.dromara.easyes.annotation.Settings;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@IndexName("EasyesDocument")
@Settings(shardsNum = 3, replicasNum = 2)
@Data
public class EasyesDocument {
// Fields
private String authorName;
private BigDecimal bigNum;
private Date gmtCreate;
private String caseTest;
private String creator;
private String nullField;
private String address;
private String geoLocation;
private String subTitle;
private String multiField;
private String wula;
private Integer starNum;
private String ipAddress;
private String title;
private String content;
private List<User> users;
private String filedData;
private String english;
private String commentContent;
private String location;
private Object vector;
}

View File

@ -0,0 +1,10 @@
package org.dromara.easyes.test.generated;
import lombok.Data;
@Data
public class Faq {
// Fields
private String answer;
private String faqName;
}

View File

@ -0,0 +1,14 @@
package org.dromara.easyes.test.generated;
import lombok.Data;
import java.util.List;
@Data
public class User {
// Fields
private List<Faq> faqs;
private String password;
private String userName;
private Integer age;
}

View File

@ -0,0 +1,13 @@
package org.dromara.easyes.test.mapper;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.test.entity.Author;
/**
* 父子类型-子文档的mapper
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
public interface AuthorMapper extends BaseEsMapper<Author> {
}

View File

@ -0,0 +1,13 @@
package org.dromara.easyes.test.mapper;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.test.entity.Comment;
/**
* 父子类型-子文档的mapper
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public interface CommentMapper extends BaseEsMapper<Comment> {
}

View File

@ -0,0 +1,13 @@
package org.dromara.easyes.test.mapper;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.test.entity.Contact;
/**
* 父子类型-子文档的mapper
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
public interface ContactMapper extends BaseEsMapper<Contact> {
}

View File

@ -0,0 +1,27 @@
package org.dromara.easyes.test.mapper;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.dromara.easyes.core.kernel.EsWrappers;
import org.dromara.easyes.test.entity.Document;
import java.util.List;
/**
* mapper 相当于Mybatis-plus的mapper
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public interface DocumentMapper extends BaseEsMapper<Document> {
/**
* 演示mapper中添加default方法
*
* @return document列表
*/
default List<Document> testDefaultMethod() {
LambdaEsQueryWrapper<Document> wrapper = EsWrappers.lambdaQuery(Document.class)
.eq(Document::getTitle, "测试文档4").match(Document::getContent, "内容");
return selectList(wrapper);
}
}

View File

@ -0,0 +1,22 @@
package org.dromara.easyes.test.settings;
import org.dromara.easyes.annotation.rely.DefaultSettingsProvider;
import java.util.HashMap;
import java.util.Map;
/**
* 由于es索引的settings灵活多变,框架只能针对一部分场景作简化,其余场景需要用户自定义实现
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
public class MySettingsProvider extends DefaultSettingsProvider {
@Override
public Map<String, Object> getSettings() {
// TODO 这里可以自定义你的settings实现,将自定义的settings置入map并返回即可
Map<String, Object> mySettings = new HashMap<>();
// 例如指定查询操作的慢日志阈值为30秒,当查询操作的执行时间超过此阈值时Elasticsearch会记录相应的慢日志并发出警告
mySettings.put("index.search.slowlog.threshold.query.warn", "30s");
return mySettings;
}
}

View File

@ -0,0 +1,10 @@
easy-es.keep-alive-millis=18000
easy-es.global-config.i-kun-mode=true
easy-es.global-config.process-index-mode=manual
easy-es.global-config.async-process-index-blocking=true
easy-es.global-config.print-dsl=true
easy-es.global-config.db-config.map-underscore-to-camel-case=true
easy-es.global-config.db-config.id-type=customize
easy-es.global-config.db-config.field-strategy=not_empty
easy-es.global-config.db-config.refresh-policy=immediate
easy-es.global-config.db-config.enable-track-total-hits=true

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:easy-es.properties" />
<bean id="indexStrategyFactory" class="org.dromara.easyes.spring.factory.IndexStrategyFactory"/>
<!-- easy-es配置 -->
<bean id="mapperScannerConfigurer" class="org.dromara.easyes.spring.MapperScannerConfigurer">
<property name="basePackage" value="org.dromara.easyes.test.mapper"/>
<property name="indexStrategyFactory" ref="indexStrategyFactory"/>
</bean>
</beans>