提交 3798d544 编写于 作者: zlt2000's avatar zlt2000

新增zlt-elasticsearch-spring-boot-starter工程,支持xpack和es7.x版本

上级 1651f97e
......@@ -46,6 +46,7 @@
<spring-social-security.version>1.1.6.RELEASE</spring-social-security.version>
<commons-io.version>2.6</commons-io.version>
<servlet-api.version>4.0.1</servlet-api.version>
<spring-data-elasticsearch.version>3.2.5.RELEASE</spring-data-elasticsearch.version>
<spring-cloud-alibaba-dependencies.version>2.1.1.RELEASE</spring-cloud-alibaba-dependencies.version>
<spring-boot-dependencies.version>2.1.12.RELEASE</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>Greenwich.SR5</spring-cloud-dependencies.version>
......@@ -144,6 +145,11 @@
<artifactId>zlt-common-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-elasticsearch-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
......@@ -338,6 +344,11 @@
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>${spring-data-elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
......
......@@ -20,5 +20,6 @@
<module>zlt-auth-client-spring-boot-starter</module>
<module>zlt-sentinel-spring-boot-starter</module>
<module>zlt-common-core</module>
<module>zlt-elasticsearch-spring-boot-starter</module>
</modules>
</project>
\ No newline at end of file
<?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">
<parent>
<groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId>
<version>3.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>zlt-elasticsearch-spring-boot-starter</artifactId>
<description>elasticsearch通用组件</description>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
package com.central.es.config;
import com.central.es.properties.RestClientPoolProperties;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientBuilderCustomizer;
import org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
/**
* es自动配置
*
* @author zlt
* @date 2020/3/28
* <p>
* Blog: https://blog.csdn.net/zlt2000
* Github: https://github.com/zlt2000
*/
@EnableConfigurationProperties(RestClientPoolProperties.class)
public class RestAutoConfigure {
@Bean
public RestClientBuilderCustomizer restClientBuilderCustomizer(RestClientPoolProperties poolProperties
, RestClientProperties restProperties) {
return (builder) -> {
setRequestConfig(builder, poolProperties);
setHttpClientConfig(builder, poolProperties, restProperties);
};
}
/**
* 异步httpclient连接延时配置
*/
private void setRequestConfig(RestClientBuilder builder, RestClientPoolProperties poolProperties){
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(poolProperties.getConnectTimeOut())
.setSocketTimeout(poolProperties.getSocketTimeOut())
.setConnectionRequestTimeout(poolProperties.getConnectionRequestTimeOut());
return requestConfigBuilder;
});
}
/**
* 异步httpclient连接数配置
*/
private void setHttpClientConfig(RestClientBuilder builder, RestClientPoolProperties poolProperties, RestClientProperties restProperties){
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(poolProperties.getMaxConnectNum())
.setMaxConnPerRoute(poolProperties.getMaxConnectPerRoute());
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(restProperties::getUsername).to(username -> {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, restProperties.getPassword()));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
});
return httpClientBuilder;
});
}
@Bean
@ConditionalOnMissingBean
public ElasticsearchRestTemplate elasticsearchRestTemplate(RestHighLevelClient restHighLevelClient) {
return new ElasticsearchRestTemplate(restHighLevelClient);
}
}
package com.central.es.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
/**
* es的httpClient连接池配置
*
* @author zlt
* @date 2020/3/28
* <p>
* Blog: https://blog.csdn.net/zlt2000
* Github: https://github.com/zlt2000
*/
@Setter
@Getter
@ConfigurationProperties(prefix = "zlt.elasticsearch.rest-pool")
@RefreshScope
public class RestClientPoolProperties {
/**
* 连接超时时间
*/
private Integer connectTimeOut = 1000;
/**
* 连接超时时间
*/
private Integer socketTimeOut = 30000;
/**
* 获取连接的超时时间
*/
private Integer connectionRequestTimeOut = 500;
/**
* 最大连接数
*/
private Integer maxConnectNum = 30;
/**
* 最大路由连接数
*/
private Integer maxConnectPerRoute = 10;
}
package com.central.es.utils;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.beanutils.PropertyUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* ES查询Builder
*
* @author zlt
* @date 2020/3/28
* <p>
* Blog: https://blog.csdn.net/zlt2000
* Github: https://github.com/zlt2000
*/
@Setter
@Getter
public class SearchBuilder {
/**
* 高亮前缀
*/
private static final String HIGHLIGHTER_PRE_TAGS = "<mark>";
/**
* 高亮后缀
*/
private static final String HIGHLIGHTER_POST_TAGS = "</mark>";
private SearchRequest searchRequest;
private SearchSourceBuilder searchBuilder;
private RestHighLevelClient client;
private SearchBuilder(SearchRequest searchRequest, SearchSourceBuilder searchBuilder, RestHighLevelClient client) {
this.searchRequest = searchRequest;
this.searchBuilder = searchBuilder;
this.client = client;
}
/**
* 生成SearchBuilder实例
* @param elasticsearchTemplate
* @param indexName
*/
public static SearchBuilder builder(ElasticsearchRestTemplate elasticsearchTemplate, String indexName) {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(searchSourceBuilder);
RestHighLevelClient client = elasticsearchTemplate.getClient();
return new SearchBuilder(searchRequest, searchSourceBuilder, client);
}
/**
* 生成SearchBuilder实例
* @param elasticsearchTemplate
*/
public static SearchBuilder builder(ElasticsearchRestTemplate elasticsearchTemplate) {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(searchSourceBuilder);
RestHighLevelClient client = elasticsearchTemplate.getClient();
return new SearchBuilder(searchRequest, searchSourceBuilder, client);
}
/**
* 设置索引名
* @param indices 索引名数组
*/
public SearchBuilder setIndices(String... indices) {
if (ArrayUtil.isNotEmpty(indices)) {
searchRequest.indices(indices);
}
return this;
}
/**
* 生成queryStringQuery查询
* @param queryStr 查询关键字
*/
public SearchBuilder setStringQuery(String queryStr) {
QueryBuilder queryBuilder;
if (StrUtil.isNotEmpty(queryStr)) {
queryBuilder = QueryBuilders.queryStringQuery(queryStr);
} else {
queryBuilder = QueryBuilders.matchAllQuery();
}
searchBuilder.query(queryBuilder);
return this;
}
/**
* 设置分页
* @param page 当前页数
* @param limit 每页显示数
*/
public SearchBuilder setPage(Integer page, Integer limit) {
if (page != null && limit != null) {
searchBuilder.from((page - 1) * limit)
.size(limit);
}
return this;
}
/**
* 增加排序
* @param field 排序字段
* @param order 顺序方向
*/
public SearchBuilder addSort(String field, SortOrder order) {
if (StrUtil.isNotEmpty(field) && order != null) {
searchBuilder.sort(field, order);
}
return this;
}
/**
* 设置高亮
* @param preTags 高亮处理前缀
* @param postTags 高亮处理后缀
*/
public SearchBuilder setHighlight(String field, String preTags, String postTags) {
if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(preTags) && StrUtil.isNotEmpty(postTags)) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field(field)
.preTags(preTags)
.postTags(postTags);
searchBuilder.highlighter(highlightBuilder);
}
return this;
}
/**
* 设置是否需要高亮处理
* @param isHighlighter 是否需要高亮处理
*/
public SearchBuilder setIsHighlight(Boolean isHighlighter) {
if (BooleanUtil.isTrue(isHighlighter)) {
this.setHighlight("*"
, HIGHLIGHTER_PRE_TAGS, HIGHLIGHTER_POST_TAGS);
}
return this;
}
/**
* 设置查询路由
* @param routing 路由数组
*/
public SearchBuilder setRouting(String... routing) {
if (ArrayUtil.isNotEmpty(routing)) {
searchRequest.routing(routing);
}
return this;
}
/**
* 返回结果 SearchResponse
*/
public SearchResponse get() throws IOException {
return client.search(searchRequest, RequestOptions.DEFAULT);
}
/**
* 返回列表结果 List<JSONObject>
*/
public List<JSONObject> getList() throws IOException {
return getList(this.get().getHits());
}
/**
* 返回分页结果 PageResult<JSONObject>
*/
public PageResult<JSONObject> getPage() throws IOException {
return this.getPage(null, null);
}
/**
* 返回分页结果 PageResult<JSONObject>
* @param page 当前页数
* @param limit 每页显示
*/
public PageResult<JSONObject> getPage(Integer page, Integer limit) throws IOException {
this.setPage(page, limit);
SearchResponse response = this.get();
SearchHits searchHits = response.getHits();
long totalCnt = searchHits.getTotalHits();
List<JSONObject> list = getList(searchHits);
return PageResult.<JSONObject>builder().data(list).code(0).count(totalCnt).build();
}
/**
* 返回JSON列表数据
*/
private List<JSONObject> getList(SearchHits searchHits) {
List<JSONObject> list = new ArrayList<>();
if (searchHits != null) {
searchHits.forEach(item -> {
JSONObject jsonObject = JSON.parseObject(item.getSourceAsString());
jsonObject.put("id", item.getId());
Map<String, HighlightField> highlightFields = item.getHighlightFields();
if (highlightFields != null) {
populateHighLightedFields(jsonObject, highlightFields);
}
list.add(jsonObject);
});
}
return list;
}
/**
* 组装高亮字符
* @param result 目标对象
* @param highlightFields 高亮配置
*/
private <T> void populateHighLightedFields(T result, Map<String, HighlightField> highlightFields) {
for (HighlightField field : highlightFields.values()) {
try {
String name = field.getName();
if (!name.endsWith(".keyword")) {
PropertyUtils.setProperty(result, field.getName(), concat(field.fragments()));
}
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new ElasticsearchException("failed to set highlighted value for field: " + field.getName()
+ " with value: " + Arrays.toString(field.getFragments()), e);
}
}
}
/**
* 拼凑数组为字符串
*/
private String concat(Text[] texts) {
StringBuffer sb = new StringBuffer();
for (Text text : texts) {
sb.append(text.toString());
}
return sb.toString();
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.central.es.config.RestAutoConfigure
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册