xiangpei
2025-06-25 1cdb060a8aa59b0979f7609db1781805528e76e7
视频评论数、收藏数通过mq、redis实现
22个文件已修改
4个文件已添加
529 ■■■■ 已修改文件
config/application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
consumer/src/main/java/cn/lili/listener/CommentMessageListener.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
consumer/src/main/java/cn/lili/listener/VideoMessageListener.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/cache/CachePrefix.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/constant/RedisKeyExpireConstant.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/entity/Video.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoComment.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/KitchenVideoVO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoCommentVO.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoVO.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/domain/vo/WxVideoVO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/event/event/VideoCommentNumCacheEvent.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/event/eventListener/LmkEventListener.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/mapper/MyCollectMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/MyCollectService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/VideoCommentService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/VideoService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/MyCollectServiceImpl.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoCommentServiceImpl.java 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/java/cn/lili/rocketmq/tags/VideoTagsEnum.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/MyCollectMapper.xml 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/ThumbsUpRecordMapper.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
framework/src/main/resources/mapper/lmk/VideoCommentMapper.xml 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
lmk-job/src/main/java/cn/lili/job/VideoJob.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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);
        }