config/application.yml
@@ -284,6 +284,8 @@ promotion-group: shop_lili_promotion_group comment-topic: lmk_comment_topic # 评论 comment-group: lmk_comment_group video-topic: lmk_video_topic # 视频 video-group: lmk_video_group msg-ext-topic: shop_lili_msg_topic msg-ext-group: shop_lili_msg_group goods-topic: shop_lili_goods_topic consumer/src/main/java/cn/lili/listener/CommentMessageListener.java
@@ -1,18 +1,11 @@ package cn.lili.listener; import cn.lili.base.Result; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.security.context.UserContext; import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; import cn.lili.modules.lmk.domain.entity.VideoComment; import cn.lili.modules.lmk.domain.form.ThumbsUpRecordForm; import cn.lili.modules.lmk.service.ThumbsUpRecordService; import cn.lili.modules.lmk.service.VideoCommentService; import cn.lili.rocketmq.tags.CommentTagsEnum; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.message.MessageExt; @@ -20,9 +13,6 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * 评论消息消费者 @@ -87,7 +77,7 @@ * @param msg */ public void cancelThumbsUp(String msg) { ThumbsUpRecordForm form = JSON.parseObject(msg, ThumbsUpRecordForm.class); videoCommentService.mqCancelThumbsUp(form); ThumbsUpRecord record = JSON.parseObject(msg, ThumbsUpRecord.class); videoCommentService.mqCancelThumbsUp(record); } } consumer/src/main/java/cn/lili/listener/VideoMessageListener.java
New file @@ -0,0 +1,69 @@ package cn.lili.listener; import cn.lili.cache.Cache; import cn.lili.modules.lmk.domain.entity.MyCollect; import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; import cn.lili.modules.lmk.domain.form.ThumbsUpRecordForm; import cn.lili.modules.lmk.service.ThumbsUpRecordService; import cn.lili.modules.lmk.service.VideoCommentService; import cn.lili.modules.lmk.service.VideoService; import cn.lili.rocketmq.tags.CommentTagsEnum; import cn.lili.rocketmq.tags.VideoTagsEnum; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 评论消息消费者 * * @author paulG * @since 2020/12/9 **/ @Component @Slf4j @RocketMQMessageListener(topic = "${lili.data.rocketmq.video-topic}", consumerGroup = "${lili.data.rocketmq.video-group}") public class VideoMessageListener implements RocketMQListener<MessageExt> { @Autowired private VideoService videoService; @Autowired private Cache<Object> cache; @Override public void onMessage(MessageExt messageExt) { try { String msg = new String(messageExt.getBody()); if (StringUtils.isBlank(msg)) { log.error("video msg is null, cant not consumer"); return; } switch (VideoTagsEnum.valueOf(messageExt.getTags())) { case COLLECT: this.collect(msg); break; default: log.error("video msg not match correct tag, consumer err"); break; } } catch (Exception e) { log.error("video msg consumer err", e); } } /** * 视频收藏/取消收藏 * * @param msg */ public void collect(String msg) { MyCollect collect = JSON.parseObject(msg, MyCollect.class); videoService.mqCollectChange(collect); } } framework/src/main/java/cn/lili/cache/CachePrefix.java
@@ -519,6 +519,17 @@ VIDEO_COMMENT_LIKE_NUM, /** * 视频评论数量 */ VIDEO_COMMENT_NUM, /** * 视频收藏数量 */ VIDEO_COLLECT_NUM, /** * 扫码登录 * * @param str framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java
@@ -26,6 +26,13 @@ private String commentGroup; /** * 视频 */ private String videoTopic; private String videoGroup; private String promotionTopic; private String promotionGroup; framework/src/main/java/cn/lili/modules/lmk/constant/RedisKeyExpireConstant.java
@@ -11,10 +11,20 @@ public class RedisKeyExpireConstant { /** * 评论数 * 评论数过期时间 */ public static final Long COMMENT_NUM_EXPIRE = 15l; /** * 评论点赞数过期时间 */ public static final Long COMMENT_LIKE_NUM_EXPIRE = 15l; /** * 视频收藏数过期时间 */ public static final Long COLLECT_NUM_EXPIRE = 15l; /** * 过期时间单位 framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java
@@ -75,15 +75,23 @@ @TableField("play_num") /** 播放量 */ private Long playNum; private Integer playNum; @TableField("collect_num") /** 收藏数 */ private Long collectNum; private Integer collectNum; @TableField("comment_num") /** 评论数 */ private Long commentNum; private Integer commentNum; @TableField("collect_num_job") /** 是否需要定时任务统计收藏数 */ private Boolean collectNumJob; @TableField("comment_num_job") /** 是否需要定时任务统计评论数 */ private Boolean commentNumJob; @TableField("weight") /** 权重 */ framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoComment.java
@@ -52,7 +52,7 @@ @TableField("thumbs_up_num") /** 点赞数量 */ private Long thumbsUpNum; private Integer thumbsUpNum; @TableField("thumbs_up_job") /** 是否需要定时任务更新点赞数 */ framework/src/main/java/cn/lili/modules/lmk/domain/vo/KitchenVideoVO.java
@@ -91,11 +91,11 @@ /** 收藏数 */ @ApiModelProperty("收藏数") private Long collectNum; private Integer collectNum; /** 评论数 */ @ApiModelProperty("评论数") private Long commentNum; private Integer commentNum; /** 权重 */ @ApiModelProperty("权重") framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoCommentVO.java
@@ -56,7 +56,7 @@ private String userAvatar; @ApiModelProperty("评论点赞数") private Long thumbsUpNum; private Integer thumbsUpNum; @ApiModelProperty("主评论下面总共有多少条回复") private Long replyTotalCount; framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java
@@ -79,15 +79,15 @@ /** 播放量 */ @ApiModelProperty("播放量") private Long playNum; private Integer playNum; /** 收藏数 */ @ApiModelProperty("收藏数") private Long collectNum; private Integer collectNum; /** 评论数 */ @ApiModelProperty("评论数") private Long commentNum; private Integer commentNum; /** 权重 */ @ApiModelProperty("权重") framework/src/main/java/cn/lili/modules/lmk/domain/vo/WxVideoVO.java
@@ -83,11 +83,11 @@ /** 收藏数 */ @ApiModelProperty("收藏数") private Long collectNum; private Integer collectNum; /** 评论数 */ @ApiModelProperty("评论数") private Long commentNum; private Integer commentNum; /** 视频拥有的操作 */ @ApiModelProperty("视频支持的操作") framework/src/main/java/cn/lili/modules/lmk/event/event/VideoCommentNumCacheEvent.java
New file @@ -0,0 +1,43 @@ package cn.lili.modules.lmk.event.event; import org.springframework.context.ApplicationEvent; import java.time.Clock; /** * 缓存视频评论数量事件 * * @author:xp * @date:2025/6/25 14:52 */ public class VideoCommentNumCacheEvent extends ApplicationEvent { /** * 视频id */ private String videoId; public VideoCommentNumCacheEvent(Object source) { super(source); } public VideoCommentNumCacheEvent(Object source, Clock clock) { super(source, clock); } public String getVideoId() { return videoId; } public void setVideoId(String videoId) { this.videoId = videoId; } public VideoCommentNumCacheEvent(Object source, String videoId) { super(source); this.videoId = videoId; } } framework/src/main/java/cn/lili/modules/lmk/event/eventListener/LmkEventListener.java
New file @@ -0,0 +1,63 @@ package cn.lili.modules.lmk.event.eventListener; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; import cn.lili.modules.lmk.domain.entity.Video; import cn.lili.modules.lmk.event.event.VideoCommentNumCacheEvent; import cn.lili.modules.lmk.service.VideoService; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; import java.util.Objects; /** * 事件监听器 * * @author:xp * @date:2025/6/25 14:54 */ @Component @RequiredArgsConstructor public class LmkEventListener { private final Cache cache; private final VideoService videoService; /** * 新增视频评论时,更新视频评论数缓存 * * TransactionalEventListener TransactionPhase.BEFORE_COMMIT 表示事件发起处的事务提交之前执行该事件,能保证事务 * * @param event */ @TransactionalEventListener(classes = {VideoCommentNumCacheEvent.class}, phase = TransactionPhase.BEFORE_COMMIT) public void videoCommentNumCache(VideoCommentNumCacheEvent event) { // 初始化redis中评论的点赞数量 cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(event.getVideoId()), 0, RedisKeyExpireConstant.COMMENT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); // 处理视频评论数 Video video = videoService.getById(event.getVideoId()); if (cache.exist(CachePrefix.VIDEO_COMMENT_NUM.getPrefixWithId(event.getVideoId()))) { cache.incr(CachePrefix.VIDEO_COMMENT_NUM.getPrefixWithId(event.getVideoId())); } else { if (Objects.nonNull(video)) { cache.put(CachePrefix.VIDEO_COMMENT_NUM.getPrefixWithId(event.getVideoId()), video.getCommentNum() + 1, RedisKeyExpireConstant.COMMENT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); } } // 标识需要定时任务统计评论数量 if (Objects.nonNull(video) && ! video.getCommentNumJob()) { new LambdaUpdateChainWrapper<>(videoService.getBaseMapper()) .eq(Video::getId, event.getVideoId()) .set(Video::getCommentNumJob, Boolean.TRUE) .update(); } } } framework/src/main/java/cn/lili/modules/lmk/mapper/MyCollectMapper.java
@@ -40,12 +40,11 @@ List<SimpleMyCollectVO> getCollectsByVideoIds(@Param("videoIds") List<String> videoIds, @Param("userId") String currentUserId); /** * 根据某收藏类型id分组统计数量,比如:统计每个视频的收藏数 * 根据视频藏类型id分组统计数量,比如:统计每个视频的收藏数 * * @param type * @return */ List<CollectTypeNumVO> countNumGroupByType(@Param("type") String type); List<CollectTypeNumVO> countNumGroupByVideo(); /** framework/src/main/java/cn/lili/modules/lmk/service/MyCollectService.java
@@ -75,11 +75,11 @@ List<SimpleMyCollectVO> getCollectsByVideoIds(List<String> videoIds); /** * 根据某收藏类型id分组统计数量,比如:统计每个视频的收藏数 * @param type * 根据视频藏类型id分组统计数量,比如:统计每个视频的收藏数 * * @return */ List<CollectTypeNumVO> countNumGroupByType(String type); List<CollectTypeNumVO> countNumGroupByVideo(); Result getMyCollectList(MyCollectQuery query); } framework/src/main/java/cn/lili/modules/lmk/service/VideoCommentService.java
@@ -100,9 +100,9 @@ /** * mq的取消点赞逻辑 * * @param form * @param record */ void mqCancelThumbsUp(ThumbsUpRecordForm form); void mqCancelThumbsUp(ThumbsUpRecord record); /** * 批量更新评论点赞数 framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java
@@ -1,6 +1,7 @@ package cn.lili.modules.lmk.service; import cn.lili.group.Add; import cn.lili.modules.lmk.domain.entity.MyCollect; import cn.lili.modules.lmk.domain.entity.Video; import cn.lili.modules.lmk.domain.form.*; import cn.lili.modules.lmk.domain.query.*; @@ -257,4 +258,11 @@ * @return */ Result updatePublish(WxVideoForm form); /** * mq执行视频收藏/取消收藏 * * @param collect */ void mqCollectChange(MyCollect collect); } framework/src/main/java/cn/lili/modules/lmk/service/impl/MyCollectServiceImpl.java
@@ -1,9 +1,14 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.common.enums.CollectTypeEnum; import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.common.security.context.UserContext; import cn.lili.modules.goods.entity.vos.GoodsVO; import cn.lili.modules.lmk.domain.vo.*; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.CommentTagsEnum; import cn.lili.rocketmq.tags.VideoTagsEnum; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.MyCollect; import cn.lili.modules.lmk.mapper.MyCollectMapper; @@ -13,6 +18,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.lili.modules.lmk.domain.form.MyCollectForm; import cn.lili.modules.lmk.domain.query.MyCollectQuery; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; @@ -34,28 +40,41 @@ public class MyCollectServiceImpl extends ServiceImpl<MyCollectMapper, MyCollect> implements MyCollectService { private final MyCollectMapper myCollectMapper; private final RocketmqCustomProperties rocketmqCustomProperties; private final LmkFileServiceImpl fileService; private final RocketMQTemplate rocketMQTemplate; /** * 添加 * 收藏/取消收藏 * @param form * @return */ @Override public Result change(MyCollectForm form) { MyCollect myCollect = new LambdaQueryChainWrapper<>(baseMapper) .eq(MyCollect::getCollectType, form.getCollectType()) .eq(MyCollect::getRefId, form.getRefId()) .eq(MyCollect::getUserId, UserContext.getCurrentUserId()) .one(); if (Objects.nonNull(myCollect)) { baseMapper.deleteById(myCollect.getId()); // 视频收藏走mq if (CollectTypeEnum.video.getType().equals(form.getCollectType())) { MyCollect collect = new MyCollect(); collect.setRefId(form.getRefId()); collect.setCollectType(form.getCollectType()); collect.setUserId(UserContext.getCurrentUserId()); String destination = rocketmqCustomProperties.getVideoTopic() + ":" + VideoTagsEnum.COLLECT.name(); rocketMQTemplate.asyncSend(destination, JSON.toJSONString(collect), RocketmqSendCallbackBuilder.commonCallback()); } else { myCollect = new MyCollect(); myCollect.setRefId(form.getRefId()); myCollect.setCollectType(form.getCollectType()); myCollect.setUserId(UserContext.getCurrentUserId()); baseMapper.insert(myCollect); MyCollect myCollect = new LambdaQueryChainWrapper<>(baseMapper) .eq(MyCollect::getCollectType, form.getCollectType()) .eq(MyCollect::getRefId, form.getRefId()) .eq(MyCollect::getUserId, UserContext.getCurrentUserId()) .one(); if (Objects.nonNull(myCollect)) { baseMapper.deleteById(myCollect.getId()); } else { myCollect = new MyCollect(); myCollect.setRefId(form.getRefId()); myCollect.setCollectType(form.getCollectType()); myCollect.setUserId(UserContext.getCurrentUserId()); baseMapper.insert(myCollect); } } return Result.ok("操作成功"); } @@ -141,8 +160,8 @@ } @Override public List<CollectTypeNumVO> countNumGroupByType(String type) { return baseMapper.countNumGroupByType(type); public List<CollectTypeNumVO> countNumGroupByVideo() { return baseMapper.countNumGroupByVideo(); } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoCommentServiceImpl.java
@@ -11,6 +11,7 @@ import cn.lili.modules.lmk.domain.form.ThumbsUpRecordForm; import cn.lili.modules.lmk.domain.vo.CollectTypeNumVO; import cn.lili.modules.lmk.enums.general.VideoCommentStatusEnum; import cn.lili.modules.lmk.event.event.VideoCommentNumCacheEvent; import cn.lili.modules.lmk.service.ThumbsUpRecordService; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.CommentTagsEnum; @@ -32,6 +33,7 @@ import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; @@ -59,11 +61,7 @@ private final ThumbsUpRecordService thumbsUpRecordService; private final RocketMQTemplate rocketMQTemplate; private final RocketmqCustomProperties rocketmqCustomProperties; /** * 评论点赞数的过期时间 */ public final static long EXPIRE_TIME = 15l; private final ApplicationEventPublisher eventPublisher; /** * 添加 @@ -92,7 +90,9 @@ entity.setUserAvatar(currentUser.getFace()); baseMapper.insert(entity); // 初始化redis中评论的点赞数量 cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(entity.getId()), 0, EXPIRE_TIME, TimeUnit.DAYS); cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(entity.getId()), 0, RedisKeyExpireConstant.COMMENT_LIKE_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); // 处理视频评论数 eventPublisher.publishEvent(new VideoCommentNumCacheEvent(this, entity.getVideoId())); return Result.ok("添加成功").data(this.detail(entity.getId()).get("data")); } @@ -198,7 +198,7 @@ public void mqThumbsUp(ThumbsUpRecord record) { boolean exists = new LambdaQueryChainWrapper<>(thumbsUpRecordService.getBaseMapper()) .eq(ThumbsUpRecord::getRefId, record.getRefId()) .eq(ThumbsUpRecord::getUserId, UserContext.getCurrentUserId()) .eq(ThumbsUpRecord::getUserId, record.getUserId()) .exists(); if (exists) { return; @@ -209,7 +209,7 @@ cache.incr(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId())); } else { if (Objects.nonNull(comment)) { cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(comment.getId()), comment.getThumbsUpNum() + 1, RedisKeyExpireConstant.COMMENT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(comment.getId()), comment.getThumbsUpNum() + 1, RedisKeyExpireConstant.COMMENT_LIKE_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); } } // 标识该评论需要通过定时任务统计点赞数 @@ -223,27 +223,29 @@ @Override public Result cancelThumbsUp(ThumbsUpRecordForm form) { ThumbsUpRecord record = ThumbsUpRecordForm.getEntityByForm(form, null); record.setUserId(UserContext.getCurrentUserId()); // 走mq异步处理 String destination = rocketmqCustomProperties.getCommentTopic() + ":" + CommentTagsEnum.CANCEL_THUMBS_UP.name(); rocketMQTemplate.asyncSend(destination, JSON.toJSONString(form), RocketmqSendCallbackBuilder.commonCallback()); rocketMQTemplate.asyncSend(destination, JSON.toJSONString(record), RocketmqSendCallbackBuilder.commonCallback()); return Result.ok(); } @Override @Transactional(rollbackFor = Exception.class) public void mqCancelThumbsUp(ThumbsUpRecordForm form) { public void mqCancelThumbsUp(ThumbsUpRecord record) { new LambdaUpdateChainWrapper<>(thumbsUpRecordService.getBaseMapper()) .eq(ThumbsUpRecord::getRefId, form.getRefId()) .eq(ThumbsUpRecord::getThumbsUpType, form.getThumbsUpType()) .eq(ThumbsUpRecord::getUserId, UserContext.getCurrentUserId()) .eq(ThumbsUpRecord::getRefId, record.getRefId()) .eq(ThumbsUpRecord::getThumbsUpType, record.getThumbsUpType()) .eq(ThumbsUpRecord::getUserId, record.getUserId()) .remove(); // redis数量减一 VideoComment comment = this.getById(form.getRefId()); if (cache.exist(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(form.getRefId()))) { cache.decr(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(form.getRefId())); VideoComment comment = this.getById(record.getRefId()); if (cache.exist(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId()))) { cache.decr(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId())); } else { if (Objects.nonNull(comment)) { cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(comment.getId()), comment.getThumbsUpNum() - 1, RedisKeyExpireConstant.COMMENT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(comment.getId()), comment.getThumbsUpNum() - 1, RedisKeyExpireConstant.COMMENT_LIKE_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); } } // 标识该评论需要通过定时任务统计点赞数 @@ -256,20 +258,20 @@ } /** * 从redis中获取评论数量,如果redis中没有则将mysql中的数量写入到redis * 从redis中获取评论点赞数量,如果redis中没有则将mysql中的数量写入到redis * * @param commentId * @param mysqlNum * @return */ private long getCommentThumbsUpNum(String commentId, long mysqlNum) { private Integer getCommentThumbsUpNum(String commentId, Integer mysqlNum) { Object redisNum = cache.get(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(commentId)); if (Objects.isNull(redisNum)) { // redis中没有就把数据库的写到redis中 cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(commentId), mysqlNum, EXPIRE_TIME, TimeUnit.DAYS); cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(commentId), mysqlNum, RedisKeyExpireConstant.COMMENT_LIKE_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); return mysqlNum; } return Long.valueOf((Integer) redisNum); return (Integer) redisNum; } @Override framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java
@@ -1,6 +1,9 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.security.context.UserContext; import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; import cn.lili.modules.lmk.domain.entity.*; import cn.lili.modules.lmk.domain.form.*; import cn.lili.modules.lmk.domain.query.*; @@ -57,6 +60,7 @@ private final KitchenVideoTypeRefService kitchenVideoTypeRefService; private final VideoGoodsService videoGoodsService; private final KitchenTypeService kitchenTypeService; private final Cache cache; /** * 添加 @@ -389,6 +393,8 @@ page.getRecords().forEach(v -> { v.setTagList(tagMap.get(v.getId())); v.setCollected(CollectionUtils.isNotEmpty(collectMap.get(v.getId()))); v.setCommentNum(this.getCommentNum(v.getId(), v.getCommentNum())); v.setCollectNum(this.getCollectNum(v.getId(), v.getCollectNum())); if (VideoContentTypeEnum.VIDEO.getValue().equals(v.getVideoContentType())) { v.setVideoUrl(cosUtil.getPreviewUrl(v.getVideoFileKey())); v.setCoverUrl(cosUtil.getPreviewUrl(v.getCoverFileKey())); @@ -400,6 +406,40 @@ }); } return Result.ok().data(page.getRecords()); } /** * 从redis中获取评论数量,如果redis中没有则将mysql中的数量写入到redis * * @param videoId * @param mysqlNum * @return */ private Integer getCommentNum(String videoId, Integer mysqlNum) { Object redisNum = cache.get(CachePrefix.VIDEO_COMMENT_NUM.getPrefixWithId(videoId)); if (Objects.isNull(redisNum)) { // redis中没有就把数据库的写到redis中 cache.put(CachePrefix.VIDEO_COMMENT_NUM.getPrefixWithId(videoId), mysqlNum, RedisKeyExpireConstant.COMMENT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); return mysqlNum; } return (Integer) redisNum; } /** * 从redis中获取收藏数量,如果redis中没有则将mysql中的数量写入到redis * * @param videoId * @param mysqlNum * @return */ private Integer getCollectNum(String videoId, Integer mysqlNum) { Object redisNum = cache.get(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(videoId)); if (Objects.isNull(redisNum)) { // redis中没有就把数据库的写到redis中 cache.put(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(videoId), mysqlNum, RedisKeyExpireConstant.COLLECT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); return mysqlNum; } return (Integer) redisNum; } @Override @@ -446,6 +486,10 @@ List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 500); 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(); } } @@ -456,6 +500,10 @@ List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 500); 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(); } } @@ -709,4 +757,49 @@ .eq(KitchenVideoTypeRef::getVideoId, id)); return Result.ok("删除成功"); } /** * mq执行视频的收藏/取消收藏 * * @param collect */ @Override @Transactional(rollbackFor = Exception.class) public void mqCollectChange(MyCollect collect) { MyCollect myCollect = new LambdaQueryChainWrapper<>(myCollectService.getBaseMapper()) .eq(MyCollect::getCollectType, collect.getCollectType()) .eq(MyCollect::getRefId, collect.getRefId()) .eq(MyCollect::getUserId, collect.getUserId()) .one(); boolean add = false; if (Objects.nonNull(myCollect)) { myCollectService.removeById(myCollect.getId()); } else { myCollectService.save(collect); add = true; } // 处理缓存 Video video = baseMapper.selectById(collect.getRefId()); if (cache.exist(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(collect.getRefId()))) { if (add) { cache.incr(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(collect.getRefId())); } else { cache.decr(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(collect.getRefId())); } } else { if (Objects.nonNull(video)) { cache.put(CachePrefix.VIDEO_COLLECT_NUM.getPrefixWithId(video.getId()), video.getCollectNum() + (add ? 1 : -1), RedisKeyExpireConstant.COLLECT_NUM_EXPIRE, RedisKeyExpireConstant.EXPIRE_DAY); } } // 标识该视频需要通过定时任务统计收藏数 if (Objects.nonNull(video) && ! video.getCollectNumJob()) { new LambdaUpdateChainWrapper<>(baseMapper) .eq(Video::getId, video.getId()) .set(Video::getCollectNumJob, Boolean.TRUE) .update(); } } } framework/src/main/java/cn/lili/rocketmq/tags/VideoTagsEnum.java
New file @@ -0,0 +1,29 @@ package cn.lili.rocketmq.tags; /** * mq视频tag * * @author paulG * @since 2020/12/9 **/ public enum VideoTagsEnum { /** * 收藏 */ COLLECT("收藏"), ; private final String description; VideoTagsEnum(String description) { this.description = description; } public String description() { return description; } } framework/src/main/resources/mapper/lmk/MyCollectMapper.xml
@@ -54,16 +54,17 @@ AND ref_id IN <foreach collection="videoIds" open="(" item="videoId" close=")" separator=",">#{videoId}</foreach> </select> <select id="countNumGroupByType" parameterType="string" resultType="cn.lili.modules.lmk.domain.vo.CollectTypeNumVO"> <select id="countNumGroupByVideo" parameterType="string" resultType="cn.lili.modules.lmk.domain.vo.CollectTypeNumVO"> SELECT ref_id as id, count(id) as countNum LV.id as id, count(LMC.ref_id) as countNum FROM lmk_my_collect lmk_video LV LEFT JOIN lmk_my_collect LMC ON LV.id = LMC.ref_id AND LMC.collect_type = 'video' AND LMC.delete_flag = 0 WHERE collect_type = #{type} AND delete_flag = 0 LV.collect_num_job = 1 AND LV.delete_flag = 0 AND LV.status = '1' GROUP BY ref_id LMC.ref_id </select> framework/src/main/resources/mapper/lmk/ThumbsUpRecordMapper.xml
@@ -44,14 +44,14 @@ <select id="countNumGroupByComment" resultType="cn.lili.modules.lmk.domain.vo.CollectTypeNumVO"> SELECT LTUR.ref_id as id, LVC.id as id, count(LTUR.ref_id) as countNum FROM lmk_thumbs_up_record LTUR INNER JOIN lmk_video_comment LVC ON LTUR.ref_id = LVC.id AND LVC.thumbs_up_job = 1 AND LVC.delete_flag = 0 lmk_video_comment LVC LEFT JOIN lmk_thumbs_up_record LTUR ON LTUR.ref_id = LVC.id AND LTUR.thumbs_up_type = 'video_comment' AND LTUR.delete_flag = 0 WHERE LTUR.thumbs_up_type = 'video_comment' AND LTUR.delete_flag = 0 LVC.thumbs_up_job = 1 AND LVC.delete_flag = 0 GROUP BY LTUR.ref_id </select> framework/src/main/resources/mapper/lmk/VideoCommentMapper.xml
@@ -145,14 +145,15 @@ <select id="countNumGroupByVideo" resultType="cn.lili.modules.lmk.domain.vo.CollectTypeNumVO"> SELECT video_id as id, COUNT(*) as countNum LV.id as id, COUNT(LVC.video_id) as countNum FROM lmk_video_comment lmk_video LV LEFT JOIN lmk_video_comment LVC ON LVC.video_id = LV.id AND LVC.delete_flag = 0 AND LVC.status = 'normal' WHERE delete_flag = 0 AND status = 'normal' LV.comment_num_job = 1 AND LV.delete_flag = 0 AND LV.status = '1' GROUP BY video_id LVC.video_id </select> lmk-job/src/main/java/cn/lili/job/VideoJob.java
@@ -37,7 +37,7 @@ @XxlJob("videoCollectNumJob") public void videoCollectNumJob() throws Exception { XxlJobHelper.log("开始执行:视频收藏数统计"); List<CollectTypeNumVO> numList = myCollectService.countNumGroupByType(CollectTypeEnum.VIDEO.getValue()); List<CollectTypeNumVO> numList = myCollectService.countNumGroupByVideo(); if (CollectionUtils.isNotEmpty(numList)) { videoService.updateCollectNumBatch(numList); }