From 00f70607f5ebbc1979eccdc3b623db0a458f3d2a Mon Sep 17 00:00:00 2001 From: xiongf <2439534736@qq.com> Date: Wed, 11 Dec 2024 17:33:28 +0800 Subject: [PATCH] =?UTF-8?q?es=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=B8=B8=E7=94=A8?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=96=B9=E6=B3=95=E5=AE=9E=E7=8E=B0=E5=92=8C?= =?UTF-8?q?=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/{EsModel.java => EsBaseModel.java} | 12 +- .../basedemo/common/model/EsSearchModel.java | 81 ++++ .../cn/xf/basedemo/common/utils/EsUtil.java | 373 ++++++++++++++---- .../xf/basedemo/common/utils/StringUtil.java | 29 ++ ...ElasticsearchConfig.java => EsConfig.java} | 41 +- .../controller/business/UserController.java | 20 +- .../cn/xf/basedemo/service/UserService.java | 4 + .../service/impl/UserServiceImpl.java | 26 ++ src/main/resources/application.yml | 3 + src/main/resources/templates/login.html | 2 +- 10 files changed, 480 insertions(+), 111 deletions(-) rename src/main/java/cn/xf/basedemo/common/model/{EsModel.java => EsBaseModel.java} (59%) create mode 100644 src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java create mode 100644 src/main/java/cn/xf/basedemo/common/utils/StringUtil.java rename src/main/java/cn/xf/basedemo/config/{ElasticsearchConfig.java => EsConfig.java} (62%) diff --git a/src/main/java/cn/xf/basedemo/common/model/EsModel.java b/src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java similarity index 59% rename from src/main/java/cn/xf/basedemo/common/model/EsModel.java rename to src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java index d1a8bfd..dd32333 100644 --- a/src/main/java/cn/xf/basedemo/common/model/EsModel.java +++ b/src/main/java/cn/xf/basedemo/common/model/EsBaseModel.java @@ -7,10 +7,17 @@ import lombok.Data; * @author remaindertime * @className EsModel * @date 2024/12/10 - * @description + * @description es基础模型 */ @Data -public class EsModel { +public class EsBaseModel { + + public EsBaseModel(String indexName, String documentId, T documentModel, Class clazz) { + this.indexName = indexName; + this.documentId = documentId; + this.documentModel = documentModel; + this.clazz = clazz; + } /** * 索引名称 @@ -31,4 +38,5 @@ public class EsModel { * 映射对象类对象 */ private Class clazz; + } diff --git a/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java b/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java new file mode 100644 index 0000000..13bc030 --- /dev/null +++ b/src/main/java/cn/xf/basedemo/common/model/EsSearchModel.java @@ -0,0 +1,81 @@ +package cn.xf.basedemo.common.model; + +import lombok.Data; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * packageName cn.xf.basedemo.common.model + * @author remaindertime + * @className EsSearchModel + * @date 2024/12/11 + * @description es 搜索模型 + */ +@Data +public class EsSearchModel { + + public EsSearchModel() { + // 使用 LinkedHashMap 保持插入顺序 + this.sort = new LinkedHashMap<>(); + } + + /** + * 索引名称 + */ + private String indexName; + + /** + * 文档类型 + */ + private Class clazz; + + /** + * 页数 + */ + private Integer pageNum; + + /** + * 每页数量 + */ + private Integer pageSize; + /** + * 精准查询字段 + */ + private Map termQuery; + + /** + * 模糊查询字段(一般是text类型) + */ + private Map matchQuery; + + /** + * 排序字段规则 ({"age":"desc"}) + */ + private Map sort; + + /** + * 分组去重字段(支持的字段类型:keyword、numeric、date 和 boolean ) + */ + private String repeatField;; + + /** + * 分组嵌套查询别名 + */ + private String innerAlias; + + /** + * 分组嵌套查询数量 + */ + private Integer innerSize; + + /** + * 指定需要返回的字段 + */ + private List includes; + /** + * 指定需要排除的字段 + */ + private List excludes; + +} \ No newline at end of file diff --git a/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java b/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java index 813bd76..3b371e1 100644 --- a/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java +++ b/src/main/java/cn/xf/basedemo/common/utils/EsUtil.java @@ -1,24 +1,22 @@ package cn.xf.basedemo.common.utils; -import cn.xf.basedemo.common.model.EsModel; +import cn.xf.basedemo.common.model.EsBaseModel; +import cn.xf.basedemo.common.model.EsSearchModel; import co.elastic.clients.elasticsearch.ElasticsearchClient; -import co.elastic.clients.elasticsearch._types.FieldValue; -import co.elastic.clients.elasticsearch._types.OpType; +import co.elastic.clients.elasticsearch._types.*; import co.elastic.clients.elasticsearch._types.query_dsl.*; -import co.elastic.clients.elasticsearch.core.IndexRequest; -import co.elastic.clients.elasticsearch.core.IndexResponse; -import co.elastic.clients.elasticsearch.core.UpdateRequest; -import co.elastic.clients.elasticsearch.core.UpdateResponse; +import co.elastic.clients.elasticsearch.core.*; +import co.elastic.clients.elasticsearch.core.search.*; import co.elastic.clients.elasticsearch.indices.CreateIndexResponse; import co.elastic.clients.elasticsearch.indices.ExistsRequest; import co.elastic.clients.json.JsonData; import co.elastic.clients.transport.endpoints.BooleanResponse; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.time.DateUtils; -import org.springframework.beans.factory.annotation.Autowired; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; - +import org.springframework.util.CollectionUtils; import java.util.*; import java.util.stream.Collectors; @@ -29,19 +27,22 @@ import java.util.stream.Collectors; * @date 2024/12/10 * @description elasticsearch工具类 */ -//@Component @Slf4j +@Component public class EsUtil { -// @Autowired - private static ElasticsearchClient esClient; + public static ElasticsearchClient esClient; + + { + esClient = (ElasticsearchClient) ApplicationContextUtils.getBean("elasticsearchClient"); + } /** * 判断索引是否存在 * @param indexName * @return */ - private static boolean existIndex(String indexName) { + public static boolean existIndex(String indexName) { try { // 创建 ExistsRequest 请求 ExistsRequest request = new ExistsRequest.Builder() @@ -98,17 +99,22 @@ public class EsUtil { /** * 新增文档 - * @param esModel + * @param esBaseModel * @return */ - public static boolean addDocument(EsModel esModel) { + public static boolean addDocument(EsBaseModel esBaseModel) { try { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(esBaseModel.getDocumentModel()); + log.info("es新增文档,文档内容:{}", jsonString); // 创建 IndexRequest 实例 IndexRequest request = new IndexRequest.Builder() - .index(esModel.getIndexName()) - .id(esModel.getDocumentId()) //指定文档id,不指定会自动生成 - .document(esModel.getDocumentModel()) - .opType(OpType.Create).build(); // 只会在文档 ID 不存在时创建文档 + .index(esBaseModel.getIndexName()) + .id(esBaseModel.getDocumentId()) //指定文档id,不指定会自动生成 + .document(esBaseModel.getDocumentModel()) + .opType(OpType.Create) // 只会在文档 ID 不存在时创建文档 + .build(); + IndexResponse response = esClient.index(request); if ("created".equals(response.result())) { log.info("Document created: " + response.id()); @@ -118,22 +124,24 @@ public class EsUtil { return false; } } catch (Exception e) { - throw new RuntimeException(e); + log.error("es新增文档失败", e); + e.printStackTrace(); } + return false; } /** * 更新文档 - * @param esModel + * @param esBaseModel * @return */ - public boolean updateDocument(EsModel esModel) { + public boolean updateDocument(EsBaseModel esBaseModel) { try { UpdateRequest updateRequest = new UpdateRequest.Builder<>() - .index(esModel.getIndexName()) - .id(esModel.getDocumentId()) - .doc(esModel.getDocumentModel()).build(); - UpdateResponse updateResponse = esClient.update(updateRequest, esModel.getClazz()); + .index(esBaseModel.getIndexName()) + .id(esBaseModel.getDocumentId()) + .doc(esBaseModel.getDocumentModel()).build(); + UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz()); log.info("Document updated: " + updateResponse.id()); return true; } catch (Exception e) { @@ -144,20 +152,20 @@ public class EsUtil { /** * 更新文档指定字段(script 脚本) - * @param esModel + * @param esBaseModel * @param script 脚本内容 * @param params 传递参数内容 */ - public void updateDocumentWithScript(EsModel esModel, String script, Map params) { + public void updateDocumentWithScript(EsBaseModel esBaseModel, String script, Map params) { try { UpdateRequest updateRequest = new UpdateRequest.Builder<>() - .index(esModel.getIndexName()) - .id(esModel.getDocumentId()) + .index(esBaseModel.getIndexName()) + .id(esBaseModel.getDocumentId()) .script(s -> s.source(script)// 脚本内容:.source("ctx._source.age += params.increment") .params(params)) // 传递参数内容:.params("increment",sonData.of(5)) .build(); - UpdateResponse updateResponse = esClient.update(updateRequest, esModel.getClazz()); + UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz()); log.info("Document updated: " + updateResponse.id()); } catch (Exception e) { e.printStackTrace(); @@ -165,50 +173,218 @@ public class EsUtil { } /** - * 构建查询条件 - * @param queryMap + * 根据id查询文档 + * @param esBaseModel * @return */ - public Query createBoolQuery(Map queryMap) { - BoolQuery.Builder cQuery = new BoolQuery.Builder(); - for (Map.Entry entry : queryMap.entrySet()) { - if (Objects.isNull(entry.getValue())) { - continue; + public static T getDocumentById(EsBaseModel esBaseModel) { + try { + GetRequest getRequest = new GetRequest.Builder() + .index(esBaseModel.getIndexName()) + .id(esBaseModel.getDocumentId()) + .build(); + GetResponse getResponse = esClient.get(getRequest, esBaseModel.getClazz()); + if (getResponse.found()) { + return getResponse.source(); } - String key = entry.getKey(); - Object value = entry.getValue(); - if (value.getClass().isArray()) { //数组查询,使用 TermsQuery - Object[] values = (Object[]) entry.getValue(); - List objs = Arrays.stream(values) - .map(v -> FieldValue.of(v)) // 将每个对象转换为 FieldValue - .collect(Collectors.toList()); - cQuery.must(new TermsQuery.Builder() - .field(key) - .terms(t -> t.value(objs)) + } catch (Exception e) { + log.error("es列表查询失败", e); + } + return null; + } + + /** + * 查询文档列表 + * @param searchModel + * @return + */ + public static List getDocumentList(EsSearchModel searchModel) { + List eslist = new ArrayList<>(); + try { + SearchResponse search = esClient.search(buildSearchRequest(searchModel), searchModel.getClazz()); + if (Objects.isNull(search)) { + return eslist; + } + HitsMetadata hits = search.hits(); + if (Objects.isNull(hits)) { + return eslist; + } + List> sourceHitList = hits.hits(); + if (CollectionUtils.isEmpty(sourceHitList)) { + return eslist; + } + sourceHitList.forEach(item -> { + // 处理每个命中 + eslist.add(item.source()); + }); + return eslist; + } catch (Exception e) { + log.error("es列表查询失败", e); + } + return eslist; + } + + /** + * 查询文档数量 + * @param searchModel + * @return + */ + public static long getDocumentCount(EsSearchModel searchModel) { + try { + CountRequest.Builder countRequest = new CountRequest.Builder(); + countRequest.index(searchModel.getIndexName()); + countRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); + CountResponse count = esClient.count(countRequest.build()); + if (Objects.isNull(count)) { + log.info("es列表数量查询异常{}", searchModel); + return 0; + } + return count.count(); + } catch (Exception e) { + log.error("es列表数量查询失败", e); + } + return 0; + } + + /** + * 根据id删除文档 + * @param esBaseModel + * @return + */ + public static Boolean deleteDocumentById(EsBaseModel esBaseModel) { + try { + DeleteRequest deleteRequest = new DeleteRequest.Builder() + .index(esBaseModel.getDocumentId()) + .id(esBaseModel.getDocumentId()) + .build(); + DeleteResponse deleteResponse = esClient.delete(deleteRequest); + if ("deleted".equals(deleteResponse.result())) { + log.info("Document deleted: " + deleteResponse.id()); + return true; + } else { + log.info("Document delete failed: " + deleteResponse.id()); + return false; + } + } catch (Exception e) { + log.error("es列表删除失败", e); + } + return false; + } + + /** + * 根据条件删除文档 + * @param searchModel + * @return 删除数量 + */ + public static long deleteDocumentByQuery(EsSearchModel searchModel) { + try { + DeleteByQueryRequest.Builder deleteRequest = new DeleteByQueryRequest.Builder(); + deleteRequest.index(searchModel.getIndexName()); + deleteRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); + deleteRequest.refresh(true); //设置删除操作后是否立即刷新索引,使删除结果立即可见 + deleteRequest.timeout(new Time.Builder().time("2s").build()); //设置删除操作的超时时间 + deleteRequest.conflicts(Conflicts.Proceed); //Conflicts.Proceed:在版本冲突时继续删除操作;Conflicts.Abort:在版本冲突时中止删除操作 + DeleteByQueryResponse dResponse = esClient.deleteByQuery(deleteRequest.build()); + if (Objects.nonNull(dResponse)) { + log.info("es条件删除成功,删除数量:{}", dResponse.deleted()); + return dResponse.deleted(); + } + } catch (Exception e) { + log.error("es条件删除数据失败", e); + } + return 0; + } + + /** + * 构建搜索请求对象 + * @param searchModel + * @return + */ + private static SearchRequest buildSearchRequest(EsSearchModel searchModel) { + //定义查询对象 + SearchRequest.Builder searchRequest = new SearchRequest.Builder(); + //设置索引名称 + searchRequest.index(searchModel.getIndexName()); + //分组去重 + if (StringUtils.isNotBlank(searchModel.getRepeatField())) { + searchRequest.collapse(buildCollapse(searchModel)); + } + //设置查询条件 + searchRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery())); + //设置排序规则 + if (searchModel.getSort() != null) { + searchRequest.sort(buildSort(searchModel.getSort())); + } + //设置分页参数 + if (searchModel.getPageSize() != null && searchModel.getPageSize() != null) { + searchRequest.from(searchModel.getPageSize() * (searchModel.getPageNum() - 1)); + searchRequest.size(searchModel.getPageSize()); + } + //设置查询字段/排查字段 + SourceConfig sourceConfig = buildSourceConfig(searchModel.getIncludes(), searchModel.getExcludes()); + if (Objects.nonNull(sourceConfig)) { + searchRequest.source(sourceConfig); + } + return searchRequest.build(); + } + + /** + * 构建查询条件 + * @param termQuery + * @param matchQuery + * @return + */ + private static Query createBoolQuery(Map termQuery, Map matchQuery) { + BoolQuery.Builder cQuery = new BoolQuery.Builder(); + // TermQuery 精准匹配 + if (termQuery != null) { + for (Map.Entry entry : termQuery.entrySet()) { + if (Objects.isNull(entry.getValue())) { + continue; + } + String key = entry.getKey(); + Object value = entry.getValue(); + if (value.getClass().isArray()) { //数组查询,使用 TermsQuery + Object[] values = (Object[]) entry.getValue(); + List objs = Arrays.stream(values) + .map(v -> FieldValue.of(v)) // 将每个对象转换为 FieldValue + .collect(Collectors.toList()); + cQuery.must(new TermsQuery.Builder() + .field(key) + .terms(t -> t.value(objs)) + .build() + ._toQuery()); + } else if (value.toString().contains(" ")) { // 短语查询,使用 MatchPhraseQuery (要严格按照单词顺序字符串中有空格,短信需匹配) + cQuery.must(new MatchPhraseQuery.Builder() + .field(key) + .query(value.toString()) + .build() + ._toQuery()); + } else { // 其他情况,使用 TermQuery 精准匹配 + cQuery.must(new TermQuery.Builder() + .field(key) + .value(value.toString()) + .build() + ._toQuery()); + } + } + } + // MatchQuery 模糊匹配全文检索分词查询 + if (matchQuery != null) { + for (Map.Entry entry : matchQuery.entrySet()) { + if (Objects.isNull(entry.getValue())) { + continue; + } + cQuery.must(new MatchQuery.Builder() + .field(entry.getKey()) + .query(entry.getValue().toString()) .build() ._toQuery()); - } else if (value.toString().contains(" ")) { // 短语查询,使用 MatchPhraseQuery (要严格按照单词顺序字符串中有空格,短信需匹配) - cQuery.must(new MatchPhraseQuery.Builder() - .field(key) - .query(value.toString()) - .build() - ._toQuery()); - } else { // 其他情况,使用 TermQuery 精准匹配 - cQuery.must(new TermQuery.Builder() - .field(key) - .value(value.toString()) - .build() - ._toQuery()); - // 使用 MatchQuery 模糊匹配全文检索分词查询 -// cQuery.must(new MatchQuery.Builder() -// .field(entry.getKey()) -// .query(value.toString()) -// .build() -// ._toQuery()); } } return cQuery.build()._toQuery(); } + /** * 构建时间区间查询 * @param startTime 开始时间 @@ -216,7 +392,7 @@ public class EsUtil { * @param fieldName 时间字段 * @return */ - public Query createTimeQuery(String startTime, String endTime, String fieldName) { + public static Query createTimeQuery(String startTime, String endTime, String fieldName) { DateRangeQuery dataQuery = new DateRangeQuery.Builder() .field(fieldName) .build(); @@ -227,6 +403,67 @@ public class EsUtil { } + /** + * 设置查询字段/排查字段 + * @param includes 需要字段 + * @param excludes 排除字段 + * @return + */ + private static SourceConfig buildSourceConfig(List includes, List excludes) { + boolean isIncludes = CollectionUtils.isEmpty(includes); + boolean isExcludes = CollectionUtils.isEmpty(excludes); + //设置查询字段/排查字段 + if (isIncludes || isExcludes) { + SourceFilter.Builder sourceFilter = new SourceFilter.Builder(); + if (isIncludes) + sourceFilter.includes(includes); + if (isExcludes) + sourceFilter.excludes(excludes); + return new SourceConfig.Builder().filter(sourceFilter.build()).build(); + } + return null; + } + + + /** + * 构建分组去重 + * @param searchModel + * @return + */ + private static FieldCollapse buildCollapse(EsSearchModel searchModel) { + FieldCollapse.Builder fieldCollapse = new FieldCollapse.Builder(); + //设置分组字段 + fieldCollapse.field(searchModel.getRepeatField()); + //设置嵌套配置 + if (StringUtils.isNotBlank(searchModel.getInnerAlias())) { + InnerHits.Builder innerHits = new InnerHits.Builder(); + //设置别名 + innerHits.name(searchModel.getInnerAlias()); + //设置查询数量 + if (searchModel.getInnerSize() != null) { + innerHits.size(searchModel.getInnerSize()); + } + fieldCollapse.innerHits(InnerHits.of(i -> i.name(searchModel.getInnerAlias()).size(10))); + } + return fieldCollapse.build(); + } + + /** + * 构建排序规则 + * @param sortMap + * @return + */ + private static List buildSort(Map sortMap) { + if (sortMap == null) { + return null; + } + List sortList = new ArrayList<>(); + for (Map.Entry sort : sortMap.entrySet()) { + sortList.add(new SortOptions.Builder().field(f -> f.field(sort.getKey()).order(SortOrder.valueOf(sort.getValue()))).build()); + } + return sortList; + } + /** * 案例:组合多条件查询(关于 must、mustNot、should 条件的使用) */ diff --git a/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java b/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java new file mode 100644 index 0000000..844163a --- /dev/null +++ b/src/main/java/cn/xf/basedemo/common/utils/StringUtil.java @@ -0,0 +1,29 @@ +package cn.xf.basedemo.common.utils; + +/** + * packageName cn.xf.basedemo.common.utils + * @author remaindertime + * @className StringUtil + * @date 2024/12/11 + * @description 字符串工具类 + */ +public class StringUtil { + + /** + * 驼峰命名法转下划线命名法 + * + * @param camelCase 驼峰命名法字符串 + * @return 下划线命名法字符串 + */ + public static String camelToKebabCase(String camelCase) { + if (camelCase == null || camelCase.isEmpty()) { + return camelCase; + } + + // 使用正则表达式将大写字母前插入一个"-" + String result = camelCase.replaceAll("([a-z])([A-Z])", "$1-$2"); + + // 转换为小写 + return result.toLowerCase(); + } +} diff --git a/src/main/java/cn/xf/basedemo/config/ElasticsearchConfig.java b/src/main/java/cn/xf/basedemo/config/EsConfig.java similarity index 62% rename from src/main/java/cn/xf/basedemo/config/ElasticsearchConfig.java rename to src/main/java/cn/xf/basedemo/config/EsConfig.java index 6817e02..70e2c1c 100644 --- a/src/main/java/cn/xf/basedemo/config/ElasticsearchConfig.java +++ b/src/main/java/cn/xf/basedemo/config/EsConfig.java @@ -9,8 +9,6 @@ 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.apache.http.impl.nio.reactor.IOReactorConfig; -import org.elasticsearch.client.Node; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.springframework.beans.factory.annotation.Value; @@ -25,7 +23,7 @@ import org.springframework.stereotype.Component; * @description es工具类 */ @Component -public class ElasticsearchConfig { +public class EsConfig { @Value("${elasticsearch.host}") private String elasticsearchHost; @@ -52,43 +50,19 @@ public class ElasticsearchConfig { AuthScope.ANY, new UsernamePasswordCredentials(username, password) ); + // 自定义 RestClientBuilder 配置 RestClientBuilder restClientBuilder = RestClient.builder( - new HttpHost(elasticsearchHost, elasticsearchPort, "http") // Elasticsearch 节点地址 + new HttpHost(elasticsearchHost, elasticsearchPort, "http") ).setHttpClientConfigCallback(httpClientBuilder -> - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) // 配置认证信息 + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) // 配置认证信息 ); - - // 配置异步连接数和线程数 - restClientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> - httpAsyncClientBuilder - // 设置最大连接数和每个节点的最大连接数 - .setMaxConnTotal(1200) // 总连接数:最多可以与所有节点同时保持 1200 个连接 - .setMaxConnPerRoute(100) // 每个节点最大连接数:对于每个节点允许最多 100 个并发连接 - // 设置 IO 线程数 - .setDefaultIOReactorConfig(IOReactorConfig.custom() - .setIoThreadCount(16) // IO 线程数设置为 16,通常为 CPU 核心数的 2-4 倍 - .build()) - ); - // 配置连接超时、套接字超时、获取连接超时 restClientBuilder.setRequestConfigCallback(builder -> - builder - .setConnectTimeout(20000) // 连接超时:连接建立超时时间为 20 秒 - .setSocketTimeout(20000) // 套接字超时:请求超时,通常是 20 秒 - .setConnectionRequestTimeout(20000) // 获取连接超时:20 秒 + builder.setConnectTimeout(20000) + .setSocketTimeout(20000) + .setConnectionRequestTimeout(20000) ); - - // 配置失败监听器,自定义重试逻辑 - restClientBuilder.setFailureListener(new RestClient.FailureListener() { - @Override - public void onFailure(Node node) { - // 可自定义错误处理逻辑,如重试或记录错误 - System.out.println("Elasticsearch node failure detected: " + node); - super.onFailure(node); // 默认的失败处理 - } - }); - // 创建 RestClientTransport 和 ElasticsearchClient RestClient restClient = restClientBuilder.build(); ElasticsearchTransport transport = new RestClientTransport( @@ -96,7 +70,6 @@ public class ElasticsearchConfig { new JacksonJsonpMapper() // 使用 Jackson 进行 JSON 处理 ); - // 返回 ElasticsearchClient 实例 return new ElasticsearchClient(transport); } diff --git a/src/main/java/cn/xf/basedemo/controller/business/UserController.java b/src/main/java/cn/xf/basedemo/controller/business/UserController.java index 96f71b1..757ab8a 100644 --- a/src/main/java/cn/xf/basedemo/controller/business/UserController.java +++ b/src/main/java/cn/xf/basedemo/controller/business/UserController.java @@ -6,14 +6,9 @@ import cn.xf.basedemo.interceptor.SessionContext; import cn.xf.basedemo.model.res.LoginInfoRes; import cn.xf.basedemo.service.UserService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springdoc.core.annotations.RouterOperations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @program: xf-boot-base @@ -43,4 +38,17 @@ public class UserController { LoginUser loginUser = SessionContext.getInstance().get(); return RetObj.success(loginUser); } + + @Operation(summary = "es同步用户信息", description = "用户信息") + @GetMapping("/syncEs") + public RetObj syncEs(Long userId){ + return userService.syncEs(userId); + } + + @Operation(summary = "es查询用户信息", description = "用户信息") + @GetMapping("/getEsId") + public RetObj getEsId(Long userId){ + return userService.getEsId(userId); + } + } diff --git a/src/main/java/cn/xf/basedemo/service/UserService.java b/src/main/java/cn/xf/basedemo/service/UserService.java index 91d1dbd..7f8dc4f 100644 --- a/src/main/java/cn/xf/basedemo/service/UserService.java +++ b/src/main/java/cn/xf/basedemo/service/UserService.java @@ -13,4 +13,8 @@ import cn.xf.basedemo.model.res.LoginInfoRes; public interface UserService { RetObj login(LoginInfoRes res); + + RetObj syncEs(Long userId); + + RetObj getEsId(Long userId); } diff --git a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java index 8ae9115..7ddc1dd 100644 --- a/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java +++ b/src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java @@ -1,10 +1,13 @@ package cn.xf.basedemo.service.impl; +import cn.xf.basedemo.common.model.EsBaseModel; import cn.xf.basedemo.common.model.LoginInfo; import cn.xf.basedemo.common.model.LoginUser; import cn.xf.basedemo.common.model.RetObj; +import cn.xf.basedemo.common.utils.EsUtil; import cn.xf.basedemo.common.utils.JwtTokenUtils; import cn.xf.basedemo.common.utils.RSAUtils; +import cn.xf.basedemo.common.utils.StringUtil; import cn.xf.basedemo.config.GlobalConfig; import cn.xf.basedemo.mappers.UserMapper; import cn.xf.basedemo.model.domain.User; @@ -90,4 +93,27 @@ public class UserServiceImpl implements UserService { return RetObj.success(loginUser); } + + @Override + public RetObj syncEs(Long userId) { + User user = userMapper.selectById(userId); + if (Objects.isNull(user)) { + return RetObj.error("用户不存在"); + } + String index = StringUtil.camelToKebabCase(user.getClass().getSimpleName()); + if (!EsUtil.existIndex(index)) { + EsUtil.createIndex(index); + } + EsUtil.addDocument(new EsBaseModel(index, String.valueOf(user.getId()), user, user.getClass())); + return RetObj.success(); + } + + @Override + public RetObj getEsId(Long userId) { + Object user = EsUtil.getDocumentById(new EsBaseModel("user", String.valueOf(userId), null, User.class)); + if(Objects.nonNull(user)){ + return RetObj.success(user); + } + return RetObj.error("es中不存在该用户"); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index da4a860..1c17631 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -52,6 +52,9 @@ mybatis-plus: # 参考文章 https://zhuanlan.zhihu.com/p/145359625 management: + health: + elasticsearch: #禁用健康检查 + enabled: false endpoints: web: exposure: diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 05d3f65..9f2dd6a 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -54,7 +54,7 @@ var json = JSON.stringify(data); var cipher = this.encryptByPublicKey(json); console.log("密文 :" + cipher); - var url = "http://117.72.35.70:8089/user/login"; + var url = "http://localhost:8089/user/login"; axios.post(url, { encryptedData: cipher, })