| | |
| | | |
| | | import cn.lili.cache.Cache; |
| | | import cn.lili.cache.CachePrefix; |
| | | import cn.lili.common.properties.RocketmqCustomProperties; |
| | | import cn.lili.common.security.context.UserContext; |
| | | import cn.lili.elasticsearch.EsSuffix; |
| | | import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; |
| | | import cn.lili.modules.lmk.domain.dto.VideoEsUpdateDTO; |
| | | import cn.lili.modules.lmk.domain.entity.*; |
| | | import cn.lili.modules.lmk.domain.es.VideoIndex; |
| | | import cn.lili.modules.lmk.domain.form.*; |
| | | import cn.lili.modules.lmk.domain.query.*; |
| | | import cn.lili.modules.lmk.domain.vo.*; |
| | |
| | | import cn.lili.modules.member.entity.dos.Member; |
| | | import cn.lili.modules.member.service.FootprintService; |
| | | import cn.lili.modules.member.service.MemberService; |
| | | import cn.lili.modules.search.entity.dos.EsGoodsIndex; |
| | | import cn.lili.rocketmq.RocketmqSendCallbackBuilder; |
| | | import cn.lili.rocketmq.tags.CommentTagsEnum; |
| | | import cn.lili.rocketmq.tags.VideoTagsEnum; |
| | | import cn.lili.utils.COSUtil; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | | import org.apache.commons.collections4.ListUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.lucene.search.join.ScoreMode; |
| | | import org.apache.rocketmq.spring.core.RocketMQTemplate; |
| | | import org.elasticsearch.index.query.*; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.data.domain.PageRequest; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.data.elasticsearch.core.ElasticsearchOperations; |
| | | import org.springframework.data.elasticsearch.core.SearchHits; |
| | | import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; |
| | | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; |
| | | import org.springframework.stereotype.Service; |
| | | import lombok.RequiredArgsConstructor; |
| | | import cn.lili.utils.PageUtil; |
| | |
| | | private final KitchenTypeService kitchenTypeService; |
| | | private final Cache cache; |
| | | |
| | | /** |
| | | * 添加 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result add(WxVideoForm form) { |
| | | Video entity = WxVideoForm.getEntityByForm(form, null); |
| | | baseMapper.insert(entity); |
| | | return Result.ok("添加成功"); |
| | | } |
| | | private final RocketmqCustomProperties rocketmqCustomProperties; |
| | | private final RocketMQTemplate rocketMQTemplate; |
| | | private final ThumbsUpRecordService thumbsUpRecordService; |
| | | private final ElasticsearchOperations restTemplate; |
| | | |
| | | /** |
| | | * 修改 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result update(WxVideoForm form) { |
| | | Video entity = baseMapper.selectById(form.getId()); |
| | | @Qualifier("videoEsServiceImpl") |
| | | private final EsService esService; |
| | | |
| | | // 为空抛IllegalArgumentException,做全局异常处理 |
| | | Assert.notNull(entity, "记录不存在"); |
| | | BeanUtils.copyProperties(form, entity); |
| | | baseMapper.updateById(entity); |
| | | return Result.ok("修改成功"); |
| | | } |
| | | |
| | | /** |
| | | * 批量删除 |
| | |
| | | * @return |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Result removeById(String id) { |
| | | baseMapper.deleteById(id); |
| | | new LambdaUpdateChainWrapper<>(videoGoodsService.getBaseMapper()) |
| | | .eq(VideoGoods::getVideoId, id) |
| | | .remove(); |
| | | new LambdaUpdateChainWrapper<>(videoTagRefService.getBaseMapper()) |
| | | .eq(VideoTagRef::getVideoId, id) |
| | | .remove(); |
| | | // mq异步删除es数据 |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_DEL.name(); |
| | | rocketMQTemplate.asyncSend(destination, id, RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("删除成功"); |
| | | } |
| | | |
| | |
| | | video.setStatus(VideoStatusEnum.AUDITING.getValue()); |
| | | video.setCoverUrl(form.getCover()); |
| | | video.setVideoType(VideoTypeEnum.VIDEO.getValue()); |
| | | video.setRecommend(Boolean.FALSE); |
| | | if (VideoContentTypeEnum.IMG.getValue().equals(form.getVideoContentType())) { |
| | | video.setVideoImgs(JSON.toJSONString(form.getVideoImgs())); |
| | | } |
| | | baseMapper.insert(video); |
| | | // 2.处理标签 |
| | | List<SimpleVideoTagVO> esTagList = new ArrayList<>(2); |
| | | List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> { |
| | | VideoTagRef videoTagRef = new VideoTagRef(); |
| | | videoTagRef.setVideoId(video.getId()); |
| | |
| | | } else { |
| | | videoTagRef.setVideoTagId(tag.getId()); |
| | | } |
| | | SimpleVideoTagVO esTag = new SimpleVideoTagVO(); |
| | | esTag.setVideoId(video.getId()); |
| | | esTag.setTagName(tag.getTagName()); |
| | | esTag.setId(tag.getId()); |
| | | esTagList.add(esTag); |
| | | return videoTagRef; |
| | | }).collect(Collectors.toList()); |
| | | videoTagRefService.saveBatch(videoTagRefs); |
| | | // 3. 保存视频文件信息 |
| | | lmkFileService.addByForm(form.getFileInfo()); |
| | | // 4. 处理选择的商品 |
| | | List<VideoGoods> videoGoods = new ArrayList<>(2); |
| | | if (CollectionUtils.isNotEmpty(form.getGoodsList())) { |
| | | List<VideoGoods> videoGoods = new ArrayList<>(2); |
| | | for (int i = 0; i < form.getGoodsList().size(); i++) { |
| | | VideoGoods e = new VideoGoods(); |
| | | e.setVideoId(video.getId()); |
| | |
| | | e.setGoodsSkuId(form.getGoodsList().get(i).getGoodsSkuId()); |
| | | e.setGoodsNum(form.getGoodsList().get(i).getGoodsNum()); |
| | | e.setOrderNum(i); |
| | | videoGoods.add(e); |
| | | videoGoodsService.save(e); |
| | | } |
| | | videoGoodsService.saveBatch(videoGoods); |
| | | } |
| | | // 5. 构建es中数据,mq异步处理 |
| | | VideoIndex videoIndex = new VideoIndex(); |
| | | BeanUtils.copyProperties(video, videoIndex); |
| | | videoIndex.setAuthorName(UserContext.getCurrentUser().getNickName()); |
| | | videoIndex.setAuthorAvatar(UserContext.getCurrentUser().getFace()); |
| | | videoIndex.setCoverFileKey(video.getCoverUrl()); |
| | | List<VideoGoodsDetailVO> esGoodsList = videoGoods.stream().map(goods -> { |
| | | VideoGoodsDetailVO vo = new VideoGoodsDetailVO(); |
| | | BeanUtils.copyProperties(goods, vo); |
| | | return vo; |
| | | }).collect(Collectors.toList()); |
| | | videoIndex.setGoodsList(esGoodsList); |
| | | videoIndex.setTagList(esTagList); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_ADD_OR_UPDATE.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(videoIndex), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("发布成功,视频审核中~"); |
| | | } |
| | | |
| | |
| | | new LambdaUpdateChainWrapper<>(videoTagRefService.getBaseMapper()) |
| | | .eq(VideoTagRef::getVideoId, video.getId()) |
| | | .remove(); |
| | | List<SimpleVideoTagVO> esTagList = new ArrayList<>(2); |
| | | List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> { |
| | | VideoTagRef videoTagRef = new VideoTagRef(); |
| | | videoTagRef.setVideoId(video.getId()); |
| | |
| | | } else { |
| | | videoTagRef.setVideoTagId(tag.getId()); |
| | | } |
| | | SimpleVideoTagVO esTag = new SimpleVideoTagVO(); |
| | | esTag.setVideoId(video.getId()); |
| | | esTag.setTagName(tag.getTagName()); |
| | | esTag.setId(tag.getId()); |
| | | esTagList.add(esTag); |
| | | return videoTagRef; |
| | | }).collect(Collectors.toList()); |
| | | videoTagRefService.saveBatch(videoTagRefs); |
| | |
| | | new LambdaUpdateChainWrapper<>(videoGoodsService.getBaseMapper()) |
| | | .eq(VideoGoods::getVideoId, video.getId()) |
| | | .remove(); |
| | | List<VideoGoods> videoGoods = new ArrayList<>(2); |
| | | if (CollectionUtils.isNotEmpty(form.getGoodsList())) { |
| | | List<VideoGoods> videoGoods = new ArrayList<>(2); |
| | | for (int i = 0; i < form.getGoodsList().size(); i++) { |
| | | VideoGoods e = new VideoGoods(); |
| | | e.setVideoId(video.getId()); |
| | |
| | | } |
| | | videoGoodsService.saveBatch(videoGoods); |
| | | } |
| | | // 5. 更新es中的数据,mq异步处理 |
| | | VideoIndex videoIndex = new VideoIndex(); |
| | | BeanUtils.copyProperties(video, videoIndex); |
| | | videoIndex.setAuthorName(UserContext.getCurrentUser().getNickName()); |
| | | videoIndex.setAuthorAvatar(UserContext.getCurrentUser().getFace()); |
| | | videoIndex.setCoverFileKey(video.getCoverUrl()); |
| | | List<VideoGoodsDetailVO> esGoodsList = videoGoods.stream().map(goods -> { |
| | | VideoGoodsDetailVO vo = new VideoGoodsDetailVO(); |
| | | BeanUtils.copyProperties(goods, vo); |
| | | return vo; |
| | | }).collect(Collectors.toList()); |
| | | videoIndex.setGoodsList(esGoodsList); |
| | | videoIndex.setTagList(esTagList); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_ADD_OR_UPDATE.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(videoIndex), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("发布成功,视频审核中~"); |
| | | } |
| | | |
| | |
| | | .eq(Video::getId, form.getId()) |
| | | .set(Video::getRecommend, form.getRecommend()) |
| | | .update(); |
| | | |
| | | // mq异步更新es |
| | | Map<String, Object> fields = new HashMap<>(2); |
| | | fields.put("recommend", form.getRecommend()); |
| | | VideoEsUpdateDTO dto = new VideoEsUpdateDTO(); |
| | | dto.setId(form.getId()); |
| | | dto.setFields(fields); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_UPDATE_SOME_FIELD.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(dto), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("设置成功"); |
| | | } |
| | | |
| | |
| | | } |
| | | videoAuditRecordService.save(auditRecord); |
| | | // 2. 修改视频状态 |
| | | Map<String, Object> fields = new HashMap<>(2); |
| | | if (form.getResult()) { |
| | | video.setStatus(VideoStatusEnum.PUBLISHED.getValue()); |
| | | video.setAuditPassTime(new Date()); |
| | | |
| | | fields.put("status", VideoStatusEnum.PUBLISHED.getValue()); |
| | | } else { |
| | | video.setStatus(VideoStatusEnum.REJECT.getValue()); |
| | | fields.put("status", VideoStatusEnum.REJECT.getValue()); |
| | | } |
| | | baseMapper.updateById(video); |
| | | |
| | | // 3. mq异步更新es |
| | | VideoEsUpdateDTO dto = new VideoEsUpdateDTO(); |
| | | dto.setId(video.getId()); |
| | | dto.setFields(fields); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_UPDATE_SOME_FIELD.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(dto), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok(); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Result up(String id) { |
| | | // 1. 更新数据库 |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .eq(Video::getId, id) |
| | | .set(Video::getStatus, VideoStatusEnum.PUBLISHED.getValue()) |
| | | .update(); |
| | | // 2. mq异步更新es |
| | | Map<String, Object> fields = new HashMap<>(2); |
| | | fields.put("status", VideoStatusEnum.PUBLISHED.getValue()); |
| | | VideoEsUpdateDTO dto = new VideoEsUpdateDTO(); |
| | | dto.setId(id); |
| | | dto.setFields(fields); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_UPDATE_SOME_FIELD.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(dto), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("上架成功"); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Result down(VideoDownForm form) { |
| | | // 1. 更新数据库 |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .eq(Video::getId, form.getId()) |
| | | .set(Video::getStatus, VideoStatusEnum.DISABLE.getValue()) |
| | | .update(); |
| | | // 2. mq异步更新es |
| | | Map<String, Object> fields = new HashMap<>(2); |
| | | fields.put("status", VideoStatusEnum.DISABLE.getValue()); |
| | | VideoEsUpdateDTO dto = new VideoEsUpdateDTO(); |
| | | dto.setId(form.getId()); |
| | | dto.setFields(fields); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_UPDATE_SOME_FIELD.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(dto), RocketmqSendCallbackBuilder.commonCallback()); |
| | | // TODO 将下架原因以通知的方式告知用户 |
| | | |
| | | return Result.ok("下架成功"); |
| | | } |
| | | |
| | |
| | | .eq(Video::getId, id) |
| | | .set(Video::getStatus, VideoStatusEnum.DISABLE.getValue()) |
| | | .update(); |
| | | // 2. mq异步更新es |
| | | Map<String, Object> fields = new HashMap<>(2); |
| | | fields.put("status", VideoStatusEnum.DISABLE.getValue()); |
| | | VideoEsUpdateDTO dto = new VideoEsUpdateDTO(); |
| | | dto.setId(id); |
| | | dto.setFields(fields); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_DOC_UPDATE_SOME_FIELD.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(dto), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("下架成功"); |
| | | } |
| | | |
| | |
| | | // 推荐算法: 1. 根据用户的收藏视频的标签 2. 根据用户关注的作者的其它视频 3. 根据用户的观看记录(观看时长较长的、重复观看次数较多的) 4. 基于相似用户的观看行为来给该用户推荐 |
| | | IPage<WxVideoVO> page = PageUtil.getPage(query, WxVideoVO.class); |
| | | switch (query.getVideoFrom()) { |
| | | case "recommend": |
| | | case "recommend":// 加载推荐视频 |
| | | baseMapper.recommendVideo(page, query); |
| | | break; |
| | | case "author": |
| | | case "author": // 加载视频主页我发布的视频 |
| | | AuthorVideoQuery query1 = new AuthorVideoQuery(); |
| | | BeanUtils.copyProperties(query, query1); |
| | | query1.setAuthorId(query.getAuthorId()); |
| | | baseMapper.getAuthorVideoPage(page, query1); |
| | | break; |
| | | case "collect": |
| | | case "collect": // 加载视频主页收藏视频 |
| | | AuthorVideoQuery query2 = new AuthorVideoQuery(); |
| | | BeanUtils.copyProperties(query, query2); |
| | | query2.setAuthorId(query.getAuthorId()); |
| | | baseMapper.getAuthorCollectVideoPage(page, query2); |
| | | break; |
| | | case "like": // 加载视频主页点赞视频 |
| | | AuthorVideoQuery query3 = new AuthorVideoQuery(); |
| | | BeanUtils.copyProperties(query, query3); |
| | | query3.setAuthorId(query.getAuthorId()); |
| | | baseMapper.getAuthorLikeVideoPage(page, query3); |
| | | break; |
| | | case "search": // 加载es搜索视频 |
| | | VideoEsQuery query4 = new VideoEsQuery(); |
| | | BeanUtils.copyProperties(query, query4); |
| | | query4.setPageNumber((int) query.getPageNumber()); |
| | | query4.setPageSize((int) query.getPageSize()); |
| | | return this.esSearch(query4); |
| | | default: |
| | | break; |
| | | } |
| | |
| | | Map<String, List<SimpleVideoTagVO>> tagMap = videoTagRefService.getTagsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleVideoTagVO::getVideoId)); |
| | | Map<String, List<SimpleMyCollectVO>> collectMap =myCollectService.getCollectsByVideoIds(videoIds) |
| | | Map<String, List<SimpleMyCollectVO>> collectMap = myCollectService.getCollectsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyCollectVO::getRefId)); |
| | | Map<String, List<SimpleMyThumbsUpVO>> thumbsUpMap = thumbsUpRecordService.getThumbssByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyThumbsUpVO::getRefId)); |
| | | List<String> subscribes = mySubscribeService.getSubscribesByUserId(UserContext.getCurrentUserId()); |
| | | // 3. 获取视频临时访问地址、设置视频标签、我是否收藏、作者是否关注 |
| | | // 3. 获取视频临时访问地址、设置视频标签、我是否收藏、是否点赞、作者是否关注 |
| | | page.getRecords().forEach(v -> { |
| | | v.setTagList(tagMap.get(v.getId())); |
| | | v.setCollected(CollectionUtils.isNotEmpty(collectMap.get(v.getId()))); |
| | | v.setThumbsUp(CollectionUtils.isNotEmpty(thumbsUpMap.get(v.getId()))); |
| | | v.setCommentNum(this.getCommentNum(v.getId(), v.getCommentNum())); |
| | | v.setCollectNum(this.getCollectNum(v.getId(), v.getCollectNum())); |
| | | v.setThumbsUpNum(this.getThumbsUpNum(v.getId(), v.getThumbsUpNum())); |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(v.getVideoContentType())) { |
| | | v.setVideoUrl(cosUtil.getPreviewUrl(v.getVideoFileKey())); |
| | | v.setCoverUrl(cosUtil.getPreviewUrl(v.getCoverFileKey())); |
| | |
| | | return (Integer) redisNum; |
| | | } |
| | | |
| | | /** |
| | | * 从redis中获取点赞数量,如果redis中没有则将mysql中的数量写入到redis |
| | | * |
| | | * @param videoId |
| | | * @param mysqlNum |
| | | * @return |
| | | */ |
| | | private Integer getThumbsUpNum(String videoId, Integer mysqlNum) { |
| | | Object redisNum = cache.get(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(videoId)); |
| | | if (Objects.isNull(redisNum)) { |
| | | // redis中没有就把数据库的写到redis中 |
| | | cache.put(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(videoId), mysqlNum, RedisKeyExpireConstant.VIDEO_THUMBS_UP_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); |
| | | return mysqlNum; |
| | | } |
| | | return (Integer) redisNum; |
| | | } |
| | | |
| | | @Override |
| | | public Result healthRecommendVideo(WxHealthVideoQuery query) { |
| | | IPage<WxVideoVO> page = PageUtil.getPage(query, WxVideoVO.class); |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateCollectNumBatch(List<CollectTypeNumVO> numList) { |
| | | // 按500条数据进行拆分 |
| | | List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 500); |
| | | // 按200条数据进行拆分 |
| | | List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 200); |
| | | for (List<CollectTypeNumVO> chunk : chunks) { |
| | | baseMapper.updateCollectNumBatch(chunk); |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .in(Video::getId, chunk.stream().map(CollectTypeNumVO::getId).collect(Collectors.toList())) |
| | | .set(Video::getCollectNumJob, Boolean.FALSE) |
| | | .update(); |
| | | // 更新es的收藏数 |
| | | for (CollectTypeNumVO vo : chunk) { |
| | | Map<String, Object> fields = new HashMap<>(1); |
| | | fields.put("collectNum", vo.getCountNum()); |
| | | esService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, vo.getId(), fields); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateCommentNumBatch(List<CollectTypeNumVO> numList) { |
| | | // 按500条数据进行拆分 |
| | | List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 500); |
| | | // 按200条数据进行拆分 |
| | | List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 200); |
| | | for (List<CollectTypeNumVO> chunk : chunks) { |
| | | baseMapper.updateCommentNumBatch(chunk); |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .in(Video::getId, chunk.stream().map(CollectTypeNumVO::getId).collect(Collectors.toList())) |
| | | .set(Video::getCommentNumJob, Boolean.FALSE) |
| | | .update(); |
| | | // 更新es的评论数 |
| | | for (CollectTypeNumVO vo : chunk) { |
| | | Map<String, Object> fields = new HashMap<>(1); |
| | | fields.put("commentNum", vo.getCountNum()); |
| | | esService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, vo.getId(), fields); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | IPage<WxVideoVO> page = PageUtil.getPage(query, WxVideoVO.class); |
| | | query.setAuthorSelf(UserContext.getCurrentUserId().equals(query.getAuthorId())); |
| | | baseMapper.getAuthorVideoPage(page, query); |
| | | for (WxVideoVO vo : page.getRecords()) { |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(vo.getVideoContentType())) { |
| | | vo.setVideoUrl(cosUtil.getPreviewUrl(vo.getVideoFileKey())); |
| | | vo.setCoverUrl(cosUtil.getPreviewUrl(vo.getCoverFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(vo.getVideoContentType()) && StringUtils.isNotBlank(vo.getVideoImgs())) { |
| | | vo.setImgs(JSON.parseArray(vo.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | List<String> videoIds = page.getRecords().stream().map(WxVideoVO::getId).collect(Collectors.toList()); |
| | | Map<String, List<SimpleVideoTagVO>> tagMap = videoTagRefService.getTagsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleVideoTagVO::getVideoId)); |
| | | Map<String, List<SimpleMyCollectVO>> collectMap = myCollectService.getCollectsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyCollectVO::getRefId)); |
| | | Map<String, List<SimpleMyThumbsUpVO>> thumbsUpMap = thumbsUpRecordService.getThumbssByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyThumbsUpVO::getRefId)); |
| | | List<String> subscribes = mySubscribeService.getSubscribesByUserId(UserContext.getCurrentUserId()); |
| | | if (CollectionUtils.isNotEmpty(page.getRecords())) { |
| | | for (WxVideoVO v : page.getRecords()) { |
| | | v.setTagList(tagMap.get(v.getId())); |
| | | v.setCollected(CollectionUtils.isNotEmpty(collectMap.get(v.getId()))); |
| | | v.setThumbsUp(CollectionUtils.isNotEmpty(thumbsUpMap.get(v.getId()))); |
| | | v.setCommentNum(this.getCommentNum(v.getId(), v.getCommentNum())); |
| | | v.setCollectNum(this.getCollectNum(v.getId(), v.getCollectNum())); |
| | | v.setThumbsUpNum(this.getThumbsUpNum(v.getId(), v.getThumbsUpNum())); |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(v.getVideoContentType())) { |
| | | v.setVideoUrl(cosUtil.getPreviewUrl(v.getVideoFileKey())); |
| | | v.setCoverUrl(cosUtil.getPreviewUrl(v.getCoverFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(v.getVideoContentType()) && StringUtils.isNotBlank(v.getVideoImgs())) { |
| | | v.setImgs(JSON.parseArray(v.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | } |
| | | v.setOptions(VideoSupportOpEnum.getVideoOpByStatus(v.getStatus())); |
| | | if (CollectionUtils.isNotEmpty(v.getGoodsList())) { |
| | | v.getGoodsList().stream().forEach(goods -> { |
| | | goods.setThumbnail(cosUtil.getPreviewUrl(goods.getThumbnail())); |
| | | }); |
| | | } |
| | | v.setSubscribeThisAuthor(subscribes.contains(v.getAuthorId())); |
| | | } |
| | | |
| | | |
| | | vo.setOptions(VideoSupportOpEnum.getVideoOpByStatus(vo.getStatus())); |
| | | } |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | |
| | | public Result getAuthorCollectVideoPage(AuthorVideoQuery query) { |
| | | IPage<WxVideoVO> page = PageUtil.getPage(query, WxVideoVO.class); |
| | | baseMapper.getAuthorCollectVideoPage(page, query); |
| | | for (WxVideoVO vo : page.getRecords()) { |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(vo.getVideoContentType())) { |
| | | vo.setVideoUrl(cosUtil.getPreviewUrl(vo.getVideoFileKey())); |
| | | vo.setCoverUrl(cosUtil.getPreviewUrl(vo.getCoverFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(vo.getVideoContentType()) && StringUtils.isNotBlank(vo.getVideoImgs())) { |
| | | vo.setImgs(JSON.parseArray(vo.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | if (CollectionUtils.isNotEmpty(page.getRecords())) { |
| | | List<String> videoIds = page.getRecords().stream().map(WxVideoVO::getId).collect(Collectors.toList()); |
| | | Map<String, List<SimpleVideoTagVO>> tagMap = videoTagRefService.getTagsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleVideoTagVO::getVideoId)); |
| | | Map<String, List<SimpleMyThumbsUpVO>> thumbsUpMap = thumbsUpRecordService.getThumbssByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyThumbsUpVO::getRefId)); |
| | | List<String> subscribes = mySubscribeService.getSubscribesByUserId(UserContext.getCurrentUserId()); |
| | | for (WxVideoVO v : page.getRecords()) { |
| | | v.setTagList(tagMap.get(v.getId())); |
| | | v.setCollected(Boolean.TRUE); |
| | | v.setThumbsUp(CollectionUtils.isNotEmpty(thumbsUpMap.get(v.getId()))); |
| | | v.setCommentNum(this.getCommentNum(v.getId(), v.getCommentNum())); |
| | | v.setCollectNum(this.getCollectNum(v.getId(), v.getCollectNum())); |
| | | v.setThumbsUpNum(this.getThumbsUpNum(v.getId(), v.getThumbsUpNum())); |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(v.getVideoContentType())) { |
| | | v.setVideoUrl(cosUtil.getPreviewUrl(v.getVideoFileKey())); |
| | | v.setCoverUrl(cosUtil.getPreviewUrl(v.getCoverFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(v.getVideoContentType()) && StringUtils.isNotBlank(v.getVideoImgs())) { |
| | | v.setImgs(JSON.parseArray(v.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | } |
| | | if (CollectionUtils.isNotEmpty(v.getGoodsList())) { |
| | | v.getGoodsList().stream().forEach(goods -> { |
| | | goods.setThumbnail(cosUtil.getPreviewUrl(goods.getThumbnail())); |
| | | }); |
| | | } |
| | | v.setSubscribeThisAuthor(subscribes.contains(v.getAuthorId())); |
| | | } |
| | | vo.setCollected(Boolean.TRUE); |
| | | } |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | | |
| | | @Override |
| | | public Result getAuthorLikeVideoPage(AuthorVideoQuery query) { |
| | | IPage<WxVideoVO> page = PageUtil.getPage(query, WxVideoVO.class); |
| | | baseMapper.getAuthorLikeVideoPage(page, query); |
| | | if (CollectionUtils.isNotEmpty(page.getRecords())) { |
| | | List<String> videoIds = page.getRecords().stream().map(WxVideoVO::getId).collect(Collectors.toList()); |
| | | Map<String, List<SimpleVideoTagVO>> tagMap = videoTagRefService.getTagsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleVideoTagVO::getVideoId)); |
| | | Map<String, List<SimpleMyCollectVO>> collectMap = myCollectService.getCollectsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyCollectVO::getRefId)); |
| | | List<String> subscribes = mySubscribeService.getSubscribesByUserId(UserContext.getCurrentUserId()); |
| | | for (WxVideoVO v : page.getRecords()) { |
| | | v.setTagList(tagMap.get(v.getId())); |
| | | v.setCollected(CollectionUtils.isNotEmpty(collectMap.get(v.getId()))); |
| | | v.setThumbsUp(Boolean.TRUE); |
| | | v.setCommentNum(this.getCommentNum(v.getId(), v.getCommentNum())); |
| | | v.setCollectNum(this.getCollectNum(v.getId(), v.getCollectNum())); |
| | | v.setThumbsUpNum(this.getThumbsUpNum(v.getId(), v.getThumbsUpNum())); |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(v.getVideoContentType())) { |
| | | v.setVideoUrl(cosUtil.getPreviewUrl(v.getVideoFileKey())); |
| | | v.setCoverUrl(cosUtil.getPreviewUrl(v.getCoverFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(v.getVideoContentType()) && StringUtils.isNotBlank(v.getVideoImgs())) { |
| | | v.setImgs(JSON.parseArray(v.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | } |
| | | if (CollectionUtils.isNotEmpty(v.getGoodsList())) { |
| | | v.getGoodsList().stream().forEach(goods -> { |
| | | goods.setThumbnail(cosUtil.getPreviewUrl(goods.getThumbnail())); |
| | | }); |
| | | } |
| | | v.setSubscribeThisAuthor(subscribes.contains(v.getAuthorId())); |
| | | } |
| | | } |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | |
| | | video.setAuthorId(UserContext.getCurrentUserId()); |
| | | video.setVideoType(VideoTypeEnum.HEALTH.getValue()); |
| | | //设置填充模式 保持比例,完整显示 |
| | | video.setVideoFit("contain"); |
| | | video.setVideoFit(form.getVideoFit()); |
| | | video.setVideoContentType(VideoContentTypeEnum.VIDEO.getValue()); |
| | | video.setStatus(VideoStatusEnum.PUBLISHED.getValue()); |
| | | baseMapper.insert(video); |
| | |
| | | video.setAuthorId(UserContext.getCurrentUserId()); |
| | | video.setVideoType(VideoTypeEnum.COOK.getValue()); |
| | | //设置填充模式 保持比例,完整显示 |
| | | video.setVideoFit("contain"); |
| | | video.setVideoFit(form.getVideoFit()); |
| | | video.setVideoContentType(VideoContentTypeEnum.VIDEO.getValue()); |
| | | video.setStatus(VideoStatusEnum.PUBLISHED.getValue()); |
| | | baseMapper.insert(video); |
| | |
| | | .update(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Result recreateEsIndex() { |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.ES_RECREATE.name(); |
| | | // 消息体不能为空,随便传一个1 |
| | | rocketMQTemplate.asyncSend(destination, "1", RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok("已成功发起构建请求,稍作等待后便会自动完成"); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Result changeThumbsUp(ThumbsUpRecordForm form) { |
| | | // mq异步处理 |
| | | ThumbsUpRecord thumbsUp = new ThumbsUpRecord(); |
| | | thumbsUp.setRefId(form.getRefId()); |
| | | thumbsUp.setThumbsUpType(ThumbsUpTypeEnum.VIDEO.getValue()); |
| | | thumbsUp.setUserId(UserContext.getCurrentUserId()); |
| | | String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.THUMBS_UP.name(); |
| | | rocketMQTemplate.asyncSend(destination, JSON.toJSONString(thumbsUp), RocketmqSendCallbackBuilder.commonCallback()); |
| | | return Result.ok(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void mqChangeThumbsUp(ThumbsUpRecord thumbsUpRecord) { |
| | | ThumbsUpRecord exists = new LambdaQueryChainWrapper<>(thumbsUpRecordService.getBaseMapper()) |
| | | .eq(ThumbsUpRecord::getUserId, thumbsUpRecord.getUserId()) |
| | | .eq(ThumbsUpRecord::getRefId, thumbsUpRecord.getRefId()) |
| | | .eq(ThumbsUpRecord::getThumbsUpType, thumbsUpRecord.getThumbsUpType()) |
| | | .one(); |
| | | boolean add = false; |
| | | if (Objects.nonNull(exists)) { |
| | | // 取消点赞 |
| | | thumbsUpRecordService.removeById(exists.getId()); |
| | | } else { |
| | | // 点赞 |
| | | thumbsUpRecordService.save(thumbsUpRecord); |
| | | add = true; |
| | | } |
| | | // 处理缓存 |
| | | Video video = baseMapper.selectById(thumbsUpRecord.getRefId()); |
| | | if (cache.exist(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(thumbsUpRecord.getRefId()))) { |
| | | if (add) { |
| | | cache.incr(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(thumbsUpRecord.getRefId())); |
| | | } else { |
| | | cache.decr(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(thumbsUpRecord.getRefId())); |
| | | } |
| | | } else { |
| | | if (Objects.nonNull(video)) { |
| | | cache.put(CachePrefix.VIDEO_THUMBS_UP_NUM.getPrefixWithId(video.getId()), |
| | | video.getThumbsUpNum() + (add ? 1 : -1), |
| | | RedisKeyExpireConstant.VIDEO_THUMBS_UP_EXPIRE, |
| | | RedisKeyExpireConstant.EXPIRE_DAY); |
| | | } |
| | | } |
| | | // 标识该视频需要通过定时任务统计收藏数 |
| | | if (Objects.nonNull(video) && ! video.getCollectNumJob()) { |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .eq(Video::getId, video.getId()) |
| | | .set(Video::getThumbsUpNumJob, Boolean.TRUE) |
| | | .update(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateThumbsUpNumBatch(List<CollectTypeNumVO> numList) { |
| | | // 按200条数据进行拆分 |
| | | List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 200); |
| | | for (List<CollectTypeNumVO> chunk : chunks) { |
| | | baseMapper.updateThumbsUpNumBatch(chunk); |
| | | new LambdaUpdateChainWrapper<>(baseMapper) |
| | | .in(Video::getId, chunk.stream().map(CollectTypeNumVO::getId).collect(Collectors.toList())) |
| | | .set(Video::getThumbsUpNumJob, Boolean.FALSE) |
| | | .update(); |
| | | // 更新es的点赞数 |
| | | for (CollectTypeNumVO vo : chunk) { |
| | | Map<String, Object> fields = new HashMap<>(1); |
| | | fields.put("thumbsUpNum", vo.getCountNum()); |
| | | esService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, vo.getId(), fields); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Result esSearch(VideoEsQuery q) { |
| | | // 判断商品索引是否存在 |
| | | if (!restTemplate.indexOps(VideoIndex.class).exists()) { |
| | | return Result.ok(); |
| | | } |
| | | q.setPageNumber(q.getPageNumber() - 1); // 前端保持统一从第一页开始,但是es从0页开始,所以减一 |
| | | // 根据点赞数排序 |
| | | Pageable pageable = PageRequest.of(q.getPageNumber(), q.getPageSize(), Sort.by(Sort.Direction.DESC, "thumbsUpNum")); |
| | | |
| | | NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); |
| | | queryBuilder.withPageable(pageable); |
| | | |
| | | if (StringUtils.isNotBlank(q.getKeyword())) { |
| | | // 1. 构建主布尔查询 |
| | | BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); |
| | | |
| | | // 2. 添加标题匹配(非嵌套字段) |
| | | boolQuery.should(QueryBuilders.matchQuery("title", q.getKeyword())); |
| | | |
| | | // 3. 添加嵌套标签匹配 |
| | | NestedQueryBuilder tagQuery = QueryBuilders.nestedQuery( |
| | | "tagList", |
| | | QueryBuilders.matchQuery("tagList.tagName", q.getKeyword()), |
| | | ScoreMode.Total // 使用总分模式 |
| | | ); |
| | | boolQuery.should(tagQuery); |
| | | |
| | | // 4. 添加嵌套商品匹配 |
| | | NestedQueryBuilder goodsQuery = QueryBuilders.nestedQuery( |
| | | "goodsList", |
| | | QueryBuilders.matchQuery("goodsList.goodsName", q.getKeyword()), |
| | | ScoreMode.Total |
| | | ); |
| | | boolQuery.should(goodsQuery); |
| | | |
| | | // 5. 设置至少匹配一个条件(OR逻辑) |
| | | boolQuery.minimumShouldMatch(1); |
| | | |
| | | // 6. 状态为已发布的 |
| | | boolQuery.must(QueryBuilders.termQuery("status", VideoStatusEnum.PUBLISHED.getValue())); |
| | | queryBuilder.withQuery(boolQuery); |
| | | } else { |
| | | return Result.ok().data(new ArrayList<>()).total(0); |
| | | } |
| | | NativeSearchQuery query = queryBuilder.build(); |
| | | SearchHits<VideoIndex> searchHits = restTemplate.search(query, VideoIndex.class); |
| | | if (CollectionUtils.isEmpty(searchHits.getSearchHits())) { |
| | | return Result.ok().data(new ArrayList<>()).total(0); |
| | | } |
| | | List<VideoIndex> data = searchHits.stream().map(hit -> hit.getContent()).collect(Collectors.toList()); |
| | | List<String> videoIds = data.stream().map(VideoIndex::getId).collect(Collectors.toList()); |
| | | // 对象转换 |
| | | Map<String, List<SimpleMyCollectVO>> collectMap = myCollectService.getCollectsByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyCollectVO::getRefId)); |
| | | Map<String, List<SimpleMyThumbsUpVO>> thumbsUpMap = thumbsUpRecordService.getThumbssByVideoIds(videoIds) |
| | | .stream() |
| | | .collect(Collectors.groupingBy(SimpleMyThumbsUpVO::getRefId)); |
| | | List<String> subscribes = mySubscribeService.getSubscribesByUserId(UserContext.getCurrentUserId()); |
| | | List<WxVideoVO> vos = data.stream().map(videoIndex -> { |
| | | WxVideoVO wxVideoVO = new WxVideoVO(); |
| | | BeanUtils.copyProperties(videoIndex, wxVideoVO); |
| | | // 判断是否关注作者、是否点赞、是否收藏 |
| | | wxVideoVO.setCollected(CollectionUtils.isNotEmpty(collectMap.get(wxVideoVO.getId()))); |
| | | wxVideoVO.setThumbsUp(CollectionUtils.isNotEmpty(thumbsUpMap.get(wxVideoVO.getId()))); |
| | | if (UserContext.getCurrentUserId().equals(wxVideoVO.getAuthorId())) { |
| | | wxVideoVO.setSubscribeThisAuthor(Boolean.TRUE); |
| | | } else { |
| | | wxVideoVO.setSubscribeThisAuthor(subscribes.contains(wxVideoVO.getAuthorId())); |
| | | } |
| | | if (VideoContentTypeEnum.VIDEO.getValue().equals(wxVideoVO.getVideoContentType())) { |
| | | wxVideoVO.setCoverUrl(cosUtil.getPreviewUrl(wxVideoVO.getCoverFileKey())); |
| | | wxVideoVO.setVideoUrl(cosUtil.getPreviewUrl(wxVideoVO.getVideoFileKey())); |
| | | } else if (VideoContentTypeEnum.IMG.getValue().equals(wxVideoVO.getVideoContentType()) && StringUtils.isNotBlank(wxVideoVO.getVideoImgs())) { |
| | | wxVideoVO.setImgs(JSON.parseArray(wxVideoVO.getVideoImgs(), String.class).stream().map(fileKey -> cosUtil.getPreviewUrl(fileKey)).collect(Collectors.toList())); |
| | | wxVideoVO.setCoverUrl(wxVideoVO.getImgs().get(0)); |
| | | } |
| | | return wxVideoVO; |
| | | }).collect(Collectors.toList()); |
| | | return Result.ok().data(vos).total(searchHits.getTotalHits()); |
| | | } |
| | | } |