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 85ccfc6..3f95953 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class differ 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 e57c2e7..19e6645 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class differ 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 c576223..353ee7b 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class differ