【Lilishop商城】No2-4.确定软件架构搭建三(本篇包括ES检索)
创始人
2024-04-13 00:54:43
0

  仅涉及后端,全部目录看顶部专栏,代码、文档、接口路径在:

【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客


全篇只介绍重点架构逻辑,具体编写看源代码就行,读起来也不复杂~

谨慎:源代码中有一些注释是错误的,有的注释意思完全相反,有的注释对不上号,我在阅读过程中就顺手更新了,并且在我不会的地方添加了新的注释,所以在读源代码过程中一定要谨慎啊!

目录

A1.ES检索

B1.ES基本搭建

B2.更新系统日志的ES存储搭建(关联No2-3)

C1.ElasticsearchRepository操作ES方式

C2.ElasticsearchOperations操作ES方式

C3.直接使用RestHighLevelClient操作ES方式(待更新)

B3.es分词查询(待更新)

剩余内容:消息中间件AMQP、定时任务等


A1.ES检索

ES学习可以看这篇文章,特别详细:ElasticSearch从入门到精通,史上最全(持续更新,未完待续,每天一点点)

我用的苹果本搭建的es和Kibana,安转时用brew安装一直报错(提示版本问题,我的本版本低了安装不了最新的),之后就直接去官网下载对应的7.3的版本的,然后直接在 bin 里面运行的,也挺方便的。

系统使用的是spring整合的es ,spring-data-elasticsearch,用的版本是Elasticsearch7.x这个版本较7.x之前使用上有些改动,虽然我没有用过之前的,但是为了防止使用混淆,还是了解了一下。

其中有一点要清楚的是spring-data-elasticsearch封装操作ES有两种方式,最终都是使用es本身的RestHighLevelClient进行的操作~

能使用RestHighLevelClient尽量使用它。

主要原因是灵活性和更新速度,Spring 将 ElasticSearch 过度封装,让开发者很难跟 ES 的 DSL 查询语句进行关联。再者就是更新速度,ES 的更新速度是非常快,但是 spring-data-elasticsearch 更新速度比较缓慢。

 具体的看这篇文章,挺清晰的:springboot2.3配置与使用elasticsearch7.x

B1.ES基本搭建

(1.ElasticsearchRepository;2.ElasticsearchOperations;3.RestHighLevelClient)

springboot本身就自带了spring-boot-starter-data-elasticsearch依赖包,我们就不用依赖了。

该系统使用的也是7.x以上版本的es,这个的配置项就不能直接使用spring的了,已经过时了,所以我们就只需要配置RestHighLevelClient的bean和ElasticsearchOperations的bean就好了,我们需要给出自定义的Properties,当然如果直接写在配置类里也行,就是不建议~

1.在frameword模块中创建Elasticsearch所需要的参数类,并在业务模块中的 yml 里配置参数项;
2.添加 elasticsearch 配置,创建RestHighLevelClient bean;

# 1.在frameword模块中创建Elasticsearch所需要的参数类,并在业务模块中的 yml 里配置参数项;//参数类,详见:cn.lili.elasticsearch.config.ElasticsearchProperties#举例 management-api 的yml配置 /lilishop-master/manager-api/src/main/resources/application.ymllili:data:# 自定义 elasticsearch 配置elasticsearch:# cluster集群cluster-name: elasticsearch# 当前连接节点所属集群的配置信息cluster-nodes: 127.0.0.1:9200index:# 默认分片的副本数number-of-replicas: 0# 默认主分片数number-of-shards: 3# 索引前缀index-prefix: lili# 协议scheme: http
#          account:
#            username: elastic
#            password: LiLiShopES
//2.添加 elasticsearch 配置,创建RestHighLevelClient bean;//详见:cn.lili.elasticsearch.config.ElasticsearchConfig@Slf4j
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {@Autowiredprivate ElasticsearchProperties elasticsearchProperties;private RestHighLevelClient client;@Override@Beanpublic RestHighLevelClient elasticsearchClient() {RestClientBuilder restBuilder = RestClient.builder(this.getHttpHosts());//修改 HTTP 客户端通信,例如添加压缩或加密层。restBuilder.setHttpClientConfigCallback(httpClientBuilder ->httpClientBuilder//自定义连接存活策略.setKeepAliveStrategy(getConnectionKeepAliveStrategy()).setMaxConnPerRoute(10).setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()));String username = elasticsearchProperties.getAccount().getUsername();String password = elasticsearchProperties.getAccount().getPassword();//如果有认证用户,就添加用户信息if (username != null && password != null) {final CredentialsProvider credential = new BasicCredentialsProvider();credential.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));//修改 HTTP 客户端通信,例如添加压缩或加密层。restBuilder.setHttpClientConfigCallback(httpClientBuilder ->httpClientBuilder.setDefaultCredentialsProvider(credential)//自定义连接存活策略.setKeepAliveStrategy(getConnectionKeepAliveStrategy()).setMaxConnPerRoute(10).setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()).build()));}//配置请求身份验证、超时和其他可以在请求级别设置的属性。restBuilder.setRequestConfigCallback(requestConfigBuilder ->requestConfigBuilder.setConnectTimeout(1000) //time until a connection with the server is established..setSocketTimeout(12 * 1000) //time of inactivity to wait for packets[data] to receive..setConnectionRequestTimeout(-1)); //time to fetch a connection from the connection pool 0 for infinite.// 创建ES客户端对象client = new RestHighLevelClient(restBuilder);return client;}/*** @Description: 配置集群服务器域名/ip* @param: []* @return: org.apache.http.HttpHost[]**/private HttpHost[] getHttpHosts() {List clusterNodes = elasticsearchProperties.getClusterNodes();HttpHost[] httpHosts = new HttpHost[clusterNodes.size()];for (int i = 0; i < clusterNodes.size(); i++) {String[] node = clusterNodes.get(i).split(":");httpHosts[i] = new HttpHost(node[0], Convert.toInt(node[1]), elasticsearchProperties.getScheme());}return httpHosts;}private ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {return (response, context) -> 2 * 60 * 1000;}/*** it gets called when bean instance is getting removed from the context if* scope is not a prototype* If there is a method named shutdown or close then spring container will try* to automatically configure them as callback methods when bean is being* destroyed*/@PreDestroypublic void clientClose() {try {this.client.close();} catch (IOException e) {log.error("es clientClose错误", e);}}}

我们在 config 里面创建了 RestHighLevelClient bean ,同时 config 又实现了 AbstractElasticsearchConfiguration ,在这个里面又创建了ElasticsearchOperations。

之后使用 ElasticsearchOperations 正常注入使用就好啦,见下面B2

ElasticsearchRepository也可以正常实现使用,见下面B2

B2.更新系统日志的ES存储搭建(关联No2-3)

之前No2-3里面系统日志框架中我们已经写了 service 类了,现在需要将具体的日志存储给加上。

C1.ElasticsearchRepository操作ES方式

集成ElasticsearchRepository方式就相当于 mps 的BaseMapper,也需要对应的实体类,实体类里面需要使用@Document标注索引。然后直接创建service类继承ElasticsearchRepository,然后直接使用就可以。

这种方式对于增删改比较方便~

1.系统日志实体类;要加上@Document标注索引,否则使用时会报错

2.系统日志Repository类,实现ElasticsearchRepository类并泛型指定为系统日志实体类;

3.系统日志业务类;

//1.系统日志实体类;要加上@Document标注索引,否则使用时会报错//详见:cn.lili.modules.permission.entity.vo.SystemLogVO@Data
//加上了@Document注解之后,默认情况下这个实体中所有的属性都会被建立索引、并且分词
//indexName 索引库的名称,个人建议以项目的名称命名;
@Document(indexName = "#{@elasticsearchProperties.indexPrefix}_" + EsSuffix.LOGS_INDEX_NAME)
@ToString
@NoArgsConstructor
public class SystemLogVO implements Serializable {。。。
}
//2.系统日志Repository类,实现ElasticsearchRepository类;
//详见:cn.lili.modules.permission.entity.vo.SystemLogVO
/*** 日志** @author paulG* @since 2021/12/13**/
public interface SystemLogRepository extends ElasticsearchRepository {}
//2.系统日志业务类;//详见:cn.lili.modules.permission.service.SystemLogService
//详见:cn.lili.modules.permission.serviceimpl.SystemLogServiceImpl//举例,
@Service
public class SystemLogServiceImpl implements SystemLogService {@Autowiredprivate SystemLogRepository systemLogRepository;/*** ES*/@Autowiredprivate ElasticsearchOperations restTemplate;@Overridepublic void saveLog(SystemLogVO systemLogVO) {systemLogRepository.save(systemLogVO);}
。。。
}

此时就可以直接调用管理员登录接口 /manager/passport/user/login 了,调用过程中会经过系统日志切面类,进而在保存日志的线程类中执行系统日志save的业务。

登录成功后,就直接去 Kibana里面搜索查看,就能查看到当前日志啦

C2.ElasticsearchOperations操作ES方式

ElasticsearchOperations方式更简单,由于我们已经通过config 创建了该 bean,所以直接在业务类中注入该bean就行,然后直接使用~

这种方式对于查询较方便

还是在SystemLogServiceImpl系统日志业务类中使用,查询日志列表;

//详见:cn.lili.modules.permission.serviceimpl.SystemLogServiceImpl@Service
public class SystemLogServiceImpl implements SystemLogService {@Autowiredprivate SystemLogRepository systemLogRepository;/*** ES*/@Autowiredprivate ElasticsearchOperations restTemplate;@Overridepublic IPage queryLog(String storeId, String operatorName, String key, SearchVO searchVo, PageVO pageVO) {pageVO.setNotConvert(true);IPage iPage = new Page<>();//查询条件构造器,可以往里面添加一些过滤或者其他条件NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();if (pageVO.getPageNumber() != null && pageVO.getPageSize() != null) {int pageNumber = pageVO.getPageNumber() - 1;if (pageNumber < 0) {pageNumber = 0;}Pageable pageable = PageRequest.of(pageNumber, pageVO.getPageSize());//添加分页条件nativeSearchQueryBuilder.withPageable(pageable);iPage.setCurrent(pageVO.getPageNumber());iPage.setSize(pageVO.getPageSize());}if (CharSequenceUtil.isNotEmpty(storeId)) {//添加查询条件nativeSearchQueryBuilder.withFilter(QueryBuilders.matchQuery("storeId", storeId));}if (CharSequenceUtil.isNotEmpty(operatorName)) {//添加查询条件nativeSearchQueryBuilder.withFilter(QueryBuilders.wildcardQuery("username", "*" + operatorName + "*"));}if (CharSequenceUtil.isNotEmpty(key)) {BoolQueryBuilder filterBuilder = new BoolQueryBuilder();filterBuilder.should(QueryBuilders.wildcardQuery("requestUrl", "*" + key + "*")).should(QueryBuilders.wildcardQuery("requestParam", "*" + key + "*")).should(QueryBuilders.wildcardQuery("responseBody", "*" + key + "*")).should(QueryBuilders.wildcardQuery("name", "*" + key + "*"));//添加查询条件nativeSearchQueryBuilder.withFilter(filterBuilder);}//时间有效性判定if (searchVo.getConvertStartDate() != null && searchVo.getConvertEndDate() != null) {BoolQueryBuilder filterBuilder = new BoolQueryBuilder();//大于方法filterBuilder.must(QueryBuilders.rangeQuery("createTime").gte(DateUtil.format(searchVo.getConvertStartDate(), "dd/MM/yyyy")).lte(DateUtil.format(searchVo.getConvertEndDate(), "dd/MM/yyyy")).format("dd/MM/yyyy||yyyy"));//添加查询条件nativeSearchQueryBuilder.withFilter(filterBuilder);}if (CharSequenceUtil.isNotEmpty(pageVO.getOrder()) && CharSequenceUtil.isNotEmpty(pageVO.getSort())) {//添加排序条件nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(pageVO.getSort()).order(SortOrder.valueOf(pageVO.getOrder().toUpperCase())));} else {//添加排序条件nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));}//执行查询SearchHits searchResult = restTemplate.search(nativeSearchQueryBuilder.build(), SystemLogVO.class);iPage.setTotal(searchResult.getTotalHits());iPage.setRecords(searchResult.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList()));return iPage;}}

注意,这里在正常业务中需要添加两个 VO ,接收前端请求传过来的日期搜索参数SearchVO和分页查询参数PageVO

【如果现在添加了,会有一系列工具类需要处理,需要添加自定义DateUtil、StringUtils】

//日期搜索参数SearchVO,详见:cn.lili.common.vo.SearchVO
//分页查询参数PageVO,详见:cn.lili.common.vo.PageVO

 添加好controller、service后,调用接口执行~记得添加token

C3.直接使用RestHighLevelClient操作ES方式(待更新)

这种更适用于查询。并且是比较推荐的。会涉及到高亮等等

我们在后面商品查询时会用到,这里先略过

B3.es分词查询(待更新)

剩余内容:消息中间件AMQP、定时任务等

相关内容

热门资讯

青岛食品招标结果:青岛食品股份... 证券之星消息,根据天眼查APP-财产线索数据整理,青岛食品股份有限公司1月11日发布《青岛食品股份有...
政策红利叠加 AI 需求爆发,... 1月12日消息,据深交所数据显示,截至10:20,深证成指上涨0.55%,创业板指下跌0.12%,中...
以制度促进科技成果就地转化 刘勇 党的二十届四中全会提出,“加快高水平科技自立自强,引领发展新质生产力。”科技成果转化作为融合创...
一场赡养纠纷 一份法治关怀 百善孝为先,赡养是刻在血脉里的本分,更是浸润岁月的温情。当青丝被岁月染白,身躯被病痛侵袭,安享晚年便...
原创 谢... 白韵琴小15岁的丈夫谢伟俊,从2008年起开始担任立法会议员直到2025年不再竞逐连任,也算是宣告一...
检察支持起诉“撑腰”,82户桃... 极目新闻通讯员 周雨欣 “感谢检察院的帮助,这笔钱我们盼了这么多年,终于要回来了!”近日,在随州市随...
“针尖”对“麦芒”?“老兰”巧... 在芮城县的街头巷尾、社区楼院,只要提起“老兰”,居民总会竖起大拇指。这位身形硬朗、目光坚毅,说话自带...
2025年全球加密资产跨链犯罪... 编者按 随着加密资产生态系统的多链格局日益深化,利用跨链技术进行洗钱等非法活动已成为全球性的突出风险...