From 93512b68d82315fadbd9ce66c43ea32472053120 Mon Sep 17 00:00:00 2001 From: Y1NanPing <735289578@qq.com> Date: Thu, 24 Jul 2025 10:56:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A1=A5=E5=85=A81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../album/api/AlbumInfoApiController.java | 3 + .../album/api/FileUploadApiController.java | 1 + .../album/config/VodConstantProperties.java | 1 + .../service/impl/BaseCategoryServiceImpl.java | 1 + .../service/impl/FileUploadServiceImpl.java | 26 ++- .../service/impl/TrackInfoServiceImpl.java | 11 +- .../album/service/impl/VodServiceImpl.java | 1 + .../search/api/SearchApiController.java | 22 ++- .../tingshu/search/service/SearchService.java | 5 + .../service/impl/SearchServiceImpl.java | 175 ++++++++++++++++++ .../search/api/SearchApiController.class | Bin 1746 -> 2666 bytes .../search/service/SearchService.class | Bin 257 -> 411 bytes .../service/impl/SearchServiceImpl.class | Bin 8643 -> 26065 bytes 13 files changed, 234 insertions(+), 12 deletions(-) diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java index 05d86ba..04cf88f 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java @@ -83,6 +83,9 @@ public class AlbumInfoApiController { * 查询当前用户专辑列表 * @return */ + + + /*这个接口是为了在声音列表中获取当前用户的所有专辑 有一个下拉框 在那里能显示内容*/ @GuiGuLogin @Operation(summary = "查询当前用户专辑列表") @GetMapping("/albumInfo/findUserAllAlbumList") diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/FileUploadApiController.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/FileUploadApiController.java index 453de31..ffde64e 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/FileUploadApiController.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/FileUploadApiController.java @@ -18,6 +18,7 @@ public class FileUploadApiController { @Autowired private FileUploadService fileUploadService; + //这个接口是将文件上传到minio上 @Operation(summary = "上传文件") @PostMapping("/fileUpload") public Result fileUpload(@RequestParam("file") MultipartFile file) throws IOException { diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/config/VodConstantProperties.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/config/VodConstantProperties.java index 69be6df..f12d45e 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/config/VodConstantProperties.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/config/VodConstantProperties.java @@ -26,6 +26,7 @@ public class VodConstantProperties { * * @return */ + //文件上传到腾讯云服务 @Bean public VodUploadClient vodUploadClient() { return new VodUploadClient(secretId, secretKey); diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.java index 0d00350..bf1427c 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.java @@ -41,6 +41,7 @@ public class BaseCategoryServiceImpl extends ServiceImpl returnList = new ArrayList<>(); //2.查询所有分类数据-查询视图即可 共计401条记录 + //获取了全部的分组数据 将其封装到了一个的集合中 List allCategoryList = baseCategoryViewMapper.selectList(null); //3.处理一级分类数据 //3.1 对所有分类集合列表进行分组按照1级分类ID进行分组 得到Map<分组ID,一级分类列表> diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/FileUploadServiceImpl.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/FileUploadServiceImpl.java index a0858c4..ac56876 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/FileUploadServiceImpl.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/FileUploadServiceImpl.java @@ -4,6 +4,7 @@ package com.atguigu.tingshu.album.service.impl; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import com.atguigu.tingshu.album.config.MinioConstantProperties; +import com.atguigu.tingshu.album.service.AuditService; import com.atguigu.tingshu.album.service.FileUploadService; import com.atguigu.tingshu.common.execption.GuiguException; import io.minio.MinioClient; @@ -25,28 +26,40 @@ public class FileUploadServiceImpl implements FileUploadService { @Autowired private MinioConstantProperties minioConstantProperties; + @Autowired + private AuditService auditService; @Override public String fileUpload(MultipartFile file) throws IOException { //1.业务校验 检验图片是否合法 BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); - if (bufferedImage == null){ - throw new GuiguException(500,"上传文件类型错误"); + if (bufferedImage == null) { + throw new GuiguException(500, "图片文件格式不合法"); } - //2.检查图片上传的大小是否合理 + + //2.业务校验:校验图片文件大小是否合法 业务限制避免上传高清图片 int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); - if(width>900||height>900){ - throw new GuiguException(500,"上传图片过大"); + if (width > 900 || height > 900) { + throw new GuiguException(500, "图片文件大小不合法"); } + + //TODO 对图片进行审核 + String suggestion = auditService.auditImage(file); + if ("block".equals(suggestion) || "review".equals(suggestion)) { + throw new GuiguException(500, "图片违规"); + } + //3.将图片文件上传MINIO 规范:日期/文件唯一命名.后缀 //3.1 生成日期作为文件夹名称 String folderName = DateUtil.today(); + //3.2 生成文件唯一名称 String extName = FileUtil.extName(file.getOriginalFilename()); String objectName = "/" + folderName + "/" + UUID.randomUUID().toString() + "." + extName; - //3.上传文件 + + //3.3 上传文件 try { minioClient.putObject( PutObjectArgs.builder().bucket(minioConstantProperties.getBucketName()).object(objectName).stream( @@ -58,7 +71,6 @@ public class FileUploadServiceImpl implements FileUploadService { throw new GuiguException(500, "上传文件到MINIO失败"); } - //4.拼接MINIO文件在线地址 return minioConstantProperties.getEndpointUrl() + "/" + minioConstantProperties.getBucketName() + objectName; } diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java index f41127e..2f2efd2 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java @@ -76,7 +76,10 @@ public class TrackInfoServiceImpl extends ServiceImpl findUserTrackPage(Page pageInfo, TrackInfoQuery trackInfoQuery) { return trackInfoMapper.findUserTrackPage(pageInfo, trackInfoQuery); diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/VodServiceImpl.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/VodServiceImpl.java index 1a631c7..fddf7ea 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/VodServiceImpl.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/VodServiceImpl.java @@ -34,6 +34,7 @@ public class VodServiceImpl implements VodService { public Map uploadTrack(MultipartFile file) { //1.首先将上传文件保存到本地临时文件夹中 后期采取定时任务去清理临时文件夹 try { + //在这个vodConstantProperties.getTempPath里改写自己的临时缓存地址 String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file); //2.上传到腾讯云点播平台 //2.1 构造上传请求对象 diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java index bac60fc..f8652b3 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java @@ -1,14 +1,13 @@ package com.atguigu.tingshu.search.api; import com.atguigu.tingshu.common.result.Result; +import com.atguigu.tingshu.query.search.AlbumIndexQuery; import com.atguigu.tingshu.search.service.SearchService; +import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Tag(name = "搜索专辑管理") @RestController @@ -40,6 +39,21 @@ public class SearchApiController { searchService.lowerAlbum(albumId); return Result.ok(); } +/** + * 站内多条件检索 + * + * @param albumIndexQuery + * @return + */ + //传出的是AlbumSearchResponseVo 这个vo类 + // 前端传过来的是AlbumIndexQuery这个实体类 + @Operation(summary = "站内多条件检索") + @PostMapping("/albumInfo") + public Result search(@RequestBody AlbumIndexQuery albumIndexQuery){ + AlbumSearchResponseVo albumSearchResponseVo=searchService.search(albumIndexQuery); + return Result.ok(albumSearchResponseVo); + + } } diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java index 65c4e9d..2548b5b 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java @@ -1,9 +1,14 @@ package com.atguigu.tingshu.search.service; +import com.atguigu.tingshu.query.search.AlbumIndexQuery; +import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo; + public interface SearchService { void upperAlbum(Long albumId); void lowerAlbum(Long albumId); + + AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery); } diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java index aba9544..59de3dc 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java @@ -4,23 +4,35 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.RandomUtil; +import co.elastic.clients.elasticsearch.ElasticsearchClient; +import co.elastic.clients.elasticsearch._types.SortOrder; +import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery; +import co.elastic.clients.elasticsearch.core.SearchRequest; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; import com.atguigu.tingshu.album.AlbumFeignClient; import com.atguigu.tingshu.model.album.AlbumAttributeValue; import com.atguigu.tingshu.model.album.AlbumInfo; import com.atguigu.tingshu.model.album.BaseCategoryView; import com.atguigu.tingshu.model.search.AlbumInfoIndex; import com.atguigu.tingshu.model.search.AttributeValueIndex; +import com.atguigu.tingshu.query.search.AlbumIndexQuery; import com.atguigu.tingshu.search.repository.AlbumInfoIndexRepository; import com.atguigu.tingshu.search.service.SearchService; import com.atguigu.tingshu.user.client.UserFeignClient; +import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo; +import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo; import com.atguigu.tingshu.vo.user.UserInfoVo; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.IOException; import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -40,6 +52,8 @@ public class SearchServiceImpl implements SearchService { private AlbumFeignClient albumFeignClient; @Autowired private UserFeignClient userFeignClient; + @Autowired + private ElasticsearchClient elasticsearchClient; @Override @@ -122,4 +136,165 @@ public class SearchServiceImpl implements SearchService { public void lowerAlbum(Long albumId) { albumInfoIndexRepository.deleteById(albumId); } + + + /*可以将这个想成kibana中开发工具哪个 buildDsl可以想象成左侧我们写的数据 我们在写 + buildDSL这个方法的时候就是在拼接这个dsl语句 + 第二步执行检索的时候就是在执行那个播放键 + 第三步就是在看右边的数据 我们要对这个数据进行分析*/ + @Override + public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) { + //一、构建检索请求对象 + try { + SearchRequest searchRequest = this.buildDSL(albumIndexQuery); + //打印出来DSL + System.err.println("本次检索DSL,复制到Kibana验证:"); + System.err.println(searchRequest.toString()); + //二、执行检索 + SearchResponse searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class); + //三.分析数据 + return this.parseResult(searchResponse, albumIndexQuery); + } catch (IOException e) { + log.error("执行检索失败:{}", e.getMessage()); + throw new RuntimeException(e); + } + + } + + + + private static final String INDEX_NAME = "albuminfo"; + + + //创建一个构建器 + private SearchRequest buildDSL(AlbumIndexQuery albumIndexQuery) { + //创建一个构建器 + SearchRequest.Builder builder = new SearchRequest.Builder(); + //创建一个索引库,名字为albuminfo + builder.index(INDEX_NAME); + + //3.逐项封装请求体参数 + //3.1 设置请求体参数"query"查询条件 + //3.1.1 创建bool查询组合三大查询条件 + BoolQuery.Builder allConditionBoolQueryBuilder = new BoolQuery.Builder(); + //3.1.2 处理关键字查询条件 + String keyword = albumIndexQuery.getKeyword(); + if (StringUtils.isNotBlank(keyword)) { + allConditionBoolQueryBuilder.must(m -> m.match(m1 -> m1.field("albumTitle").query(keyword))); + } + //3.1.3 处理1,2,3级分类过滤条件 + Long category1Id = albumIndexQuery.getCategory1Id(); + if (category1Id != null) { + allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(category1Id))); + } + Long category2Id = albumIndexQuery.getCategory2Id(); + if (category2Id != null) { + allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(category2Id))); + } + Long category3Id = albumIndexQuery.getCategory3Id(); + if (category3Id != null) { + allConditionBoolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(category3Id))); + } + //3.1.4 处理多组标签过滤条件 标签id:标签值id + List attributeList = albumIndexQuery.getAttributeList(); + if (CollUtil.isNotEmpty(attributeList)) { + //我们就循环遍历这个List集合 List集合每一个都是一个(标签值:标签内容值)的组合对 + for (String attribute : attributeList) { + String[] split = attribute.split(":"); + if (split != null && split.length == 2) { + allConditionBoolQueryBuilder.filter(f -> f.nested( + n -> n.path("attributeValueIndexList") + .query(q-> q.bool(b->b.must(m->m.term(t->t.field("attributeValueIndexList.attributeId").value(split[0]))) + .must(m->m.term(t->t.field("attributeValueIndexList.valueId").value(split[1]))))))); + } + } + } + //这个是将bool查询变成query 方便到时候查询 + builder.query(allConditionBoolQueryBuilder.build()._toQuery()); + + //3.2 设置请求体参数"from","size"分页 + //直接从前端返过来数据拿出来,将总数-1乘size,获取总数 + Integer pageNo = albumIndexQuery.getPageNo(); + Integer pageSize = albumIndexQuery.getPageSize(); + int from = (pageNo - 1) * pageSize; + builder.from(from).size(pageSize); + //3.3 设置请求体参数"highlight"高亮 + + //如果关键词不为空 那么我们就套写highlight内的数据 + //builder.highlight说明是高亮 内容接着嵌套 h.fields里面是下一层的fields 再h1就是fields里面的 + //preTags和postTags + if (StringUtils.isNotBlank(keyword)) { + builder.highlight(h -> h.fields("albumTitle", h1 -> h1.preTags("").postTags(""))); + } + //3.4 设置请求体参数"sort"排序 形式:高亮字段(1,2,3):排序规则 + //具体规则是"排序(综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc];asc:升序 desc:降序)" + //从传过来的前端数据中我们将拿到排序字段,先判断是否为空 如果不为空我们就将其根据冒号分割 + //分割成一个数组 0号索引是排序字段 1号索引是排序方向 + String order = albumIndexQuery.getOrder(); + if (StringUtils.isNotBlank(order)) { + String[] split = order.split(":"); + if (split != null && split.length == 2) { + String orderField = ""; + switch (split[0]) { + case "1": + orderField = "hotScore"; + break; + case "2": + orderField = "playStatNum"; + break; + case "3": + orderField = "createTime"; + break; + } + String finalorderField = orderField; + //判断一下是升序还是降序 + SortOrder sortOrder = split[1].equals("asc") ? SortOrder.Asc : SortOrder.Desc; + builder.sort(s -> s.field(f -> f.field(finalorderField).order(sortOrder))); + } + } + //3.5 设置请求体参数"_source"指定字段响应 + builder.source(s -> s.filter(f -> f.excludes("attributeValueIndexList", + "hotScore", + "commentStatNum", + "buyStatNum", + "subscribeStatNum", + "announcerName"))); + //4.基于检索对象构建器对象返回实际检索请求对象 + return builder.build(); + } + private AlbumSearchResponseVo parseResult(SearchResponse searchResponse, AlbumIndexQuery albumIndexQuery) { + //1.创建响应VO对象 + AlbumSearchResponseVo vo = new AlbumSearchResponseVo(); + //2.封装VO中分页相关四项属性 + //2.1 从入参直接获取页码跟页大小 + Integer pageNo = albumIndexQuery.getPageNo(); + Integer pageSize = albumIndexQuery.getPageSize(); + //2.2 从ES响应结果获取总记录数 + long total = searchResponse.hits().total().value(); + //2.3 计算总页数 + long totalPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1; + vo.setPageNo(pageNo); + vo.setPageSize(pageSize); + vo.setTotal(total); + vo.setTotalPages(totalPages); + + //3.封装VO中检索到专辑列表集合属性 + List> hits = searchResponse.hits().hits(); + if(CollUtil.isNotEmpty(hits)){ + //采用Stream流将检索到文档类型从AlbumInfoIndex转为AlbumInfoIndexVo + List list = hits.stream().map(hit -> { + AlbumInfoIndex albumInfoIndex = hit.source(); + //处理高亮字段 + Map> stringListMap = hit.highlight(); + if (CollUtil.isNotEmpty(stringListMap)) { + String hightLightText = stringListMap.get("albumTitle").get(0); + albumInfoIndex.setAlbumTitle(hightLightText); + } + return BeanUtil.copyProperties(albumInfoIndex, AlbumInfoIndexVo.class); + }).collect(Collectors.toList()); + vo.setList(list); + } + //4.响应VO对象 + return vo; + } } diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class b/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class index 85ccfc699b60537656adf69e0465796397c77da9..3f95953f92c1f584319759e2c857ae2d5cf596f7 100644 GIT binary patch delta 1029 zcmbV~Pfrt36vfY-(h{e&)}(-jLQz55f{vg?>(FYe7Ey>=j2jb^0mfQ_Gquwaaf2J( zo5qDkV?^V|jRfM~#1G)g_!$HeKZNnVnWjP)qHgBB``$VC{^rbl+x{acfBE_GGk_${ zFUe16mlu9?_|S?NckV>8;Erp#(aUb!$iqfeEcF4a5Kviyn`CD*mT z9V{%ZgdN&uD#D<^O8k+W&|=#fVF__z9@y%g2-_wKc|$8#N;=`;KOhICVKE`O)r6GF zjO(u-t=_-4`ttGG)92qmyDf11<4J!hU`VF%Up6KYfk>5k$En z>_m*4^i-d@!wW(yvj+(A+F|Qk?b=_{gMYF<^t0~(tK7r|Ab8qXc94%13x_bko58Cf z3x{!pFPjBboHvAaXB_Xd>=2{;u@yA;eZX$1n)JvU7 zF@cNMK#d_JEnvL=J-XiTp_84HM;u-Z*(_a-p`J$o2^{Aa^KwfS!|bXhli(IfyG^Pw mp%XY+PbmGHF2m}Wgj2TZv~6nVX=hlQwJ?ISd@))#p8Ew7o7Hdt delta 397 zcmbV|OG*Pl5Qe|%IF1ZDAWB3MC%#Q4(U`>N!j<3&+<6IM4v<5*6IY(V5W&a71GvmF zJcRgnkBDyFRMlVoSJ&75u{fDa-alX8fHO`<$(@a_-Mt&1#}&J*t2>RcqFhmqg36@2 zQl=c`PuNI>qoL@{Fwd&uY-wPPbtzMKgDJ9`+nL7DdlSu|s}r)|uLhld`ypkMEzNDq z6`2Hho+a6K)NU5E$W^qju!0V|I*dKlo(iK@u2X%X3BM}MABo#9EW07kEIg=HQkNu6 lk+l9v()~rU|Chwk3yb=JzNUX1P&Ez;4mr}v@y`=Zz5t=@ATa;{ diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class b/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class index e57c2e7af5ef25f9ccd1176a630619f1ec6242a1..19e6645d843199c360a8fe230e48703274d845a0 100644 GIT binary patch delta 158 zcmZoff$?3=9mm4Ez(hX7jKWrzRF9XD~8kYWPeP5Roq|O)aX_hY0FB<|LKo zdgi61Rs@2Ctu;YPjLPy+=iff$?3=9mm3_R=%OpFW$6E})XRB4>7!>G;3G&zD%jf;VifeWaBiGdpc DG2;oN diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class b/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class index c57622336257a95449adcd593bb7d8a5eb3b9398..353ee7ba31dd15e9925389b6599220aeb939c254 100644 GIT binary patch literal 26065 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 F|9}3Dlc@jz delta 2983 zcmZ8j34D`h8UH_N(l1TkHV3^61qzfTJwgwu6k2Etg?w6?_>jO6+$j&2uD4+l$25Fc z;3JR(x2&RUX>ZP{B4i8&qCJtoxNnf)bh+E~u!8>3khd)y8d_<^UHF)Wy9GXudk9|L z@|EMq!zb}64fhJ%hem=+m)*WJ+fLBf>so)*ui?{#Qdw1)Cp(&LX=Z#@+FXqL z^Z0^>`vty;FUe)D13fs7FAIDHUnN-Cv}1T+B;+3raGKu)sXID8%%D_x9uzo%Fu~5{ zX$pnH6QO~?cn8~Lz=l%-4`E6^?`rXI#TUj}RZPvHM}RX&^FXy;_TE(k<~LRCI_r6gB+3v$yn zN+Z-JQ=cxcc!~rrk%_~gbizj2r12x)d8==A_FIMLA#N}q&(PlHzPNlF*P(8iHPJ86B)|yu8SG)m1wai1hEuHo% z#*m;gDz{?;GxjUSh@f@UYNuB20ADB+7;g#sBauKvBc6sO^0{^MvLcJy!r_sLF^z5} z6f2gz)ZvVggV#@?$`Nl_1DepxC78o>I-l7(&xtuno|VrW{>_cR$;v!VNx^kxUM{nE z8Q{jy-Q}@6FW-nyljjWR6w3Hf%1=DUe-}~#{}l-hDx@O55zWPutd%Dp?mQCHl|8Vq zU>VG)Mn2ZTjds*yGkj{*Vgy0{8ABL{Fs?h?z|93-mkEc8nn%U_h#66uPYXDdd<@b; zDnT0i>ZV0Z8QEhqEoREZersq6Q|S~dWk((sCJdIQ3|uJ#SIWS}25#0j5zXU+$dd?! z=@uCH2e5ihV|CdKdH;4Gy}>7p58=c#1DfEjN0KrqLZopJ%Rq?)1#l&pn$fjsxmC?;88yo7g$VYy3kge!a<4V2a~i(|B(j zw_VRdJ+e5|9?n89viW0HjID6T(1$8)!wUYuH(>`hVi(tWH*Uio{^0m=KYzI&!hoK( zMs7Mzf?i>;n+K?ZD!J;}I8I)s4D9kQTE>*B`W;lol#xATQZ?1UWH+d(OQaOHvM(ch zi+QKTPTjtPU++XI zx=@KtI!e_{JQk_m^y+xkh5tx>#KbUR?^_B3enS zba=eml0BHk=v4Z5Ds(8_dN73FE?@WW~Rm~s80-dMm5_v}4bT40>P z^Mtc_5tzZt2L3Kzoxy)&2As#`dQ-V-nb#^#@(V_NB~-%7bPXJ+#R7)!#tPmw^{B&2 zrdIL5HE?K++)t}j>*&F$2I=7$T}^BB6zoiexih&S7=Lm>IMAlzjd8DdQAtf~VkET; z)Nm%8G_#Y0tc7K3S;qVFRczNVso^qDD6i;b?YNlwj(EB)X#@Y02Q&E?w?64usCxl2oVIDwrYKWYmGp$L3e&}mWTWo&ZKb!k4OpYLpvZ;k13DFphqu>qgd{3SL