config/application.yml
@@ -282,6 +282,8 @@ rocketmq: promotion-topic: shop_lili_promotion_topic promotion-group: shop_lili_promotion_group comment-topic: lmk_comment_topic # 评论 comment-group: lmk_comment_group msg-ext-topic: shop_lili_msg_topic msg-ext-group: shop_lili_msg_group goods-topic: shop_lili_goods_topic consumer/pom.xml
@@ -18,11 +18,7 @@ <artifactId>framework</artifactId> <version>${revision}</version> </dependency> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${xxl-job}</version> </dependency> </dependencies> <repositories> consumer/src/main/java/cn/lili/config/XxlJobConfig.java
File was deleted consumer/src/main/java/cn/lili/event/impl/DistributionOrderExecute.java
@@ -1,20 +1,11 @@ package cn.lili.event.impl; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateTime; import cn.hutool.json.JSONUtil; import cn.lili.event.AfterSaleStatusChangeEvent; import cn.lili.event.OrderStatusChangeEvent; import cn.lili.modules.distribution.entity.enums.DistributionOrderStatusEnum; import cn.lili.modules.distribution.service.DistributionOrderService; import cn.lili.modules.order.aftersale.entity.dos.AfterSale; import cn.lili.modules.order.order.entity.dto.OrderMessage; import cn.lili.modules.order.trade.entity.enums.AfterSaleStatusEnum; import cn.lili.modules.system.entity.dos.Setting; import cn.lili.modules.system.entity.dto.DistributionSetting; import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.service.SettingService; import cn.lili.timetask.handler.EveryDayExecute; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; consumer/src/main/java/cn/lili/listener/CommentMessageListener.java
New file @@ -0,0 +1,93 @@ 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; 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; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * 评论消息消费者 * * @author paulG * @since 2020/12/9 **/ @Component @Slf4j @RocketMQMessageListener(topic = "${lili.data.rocketmq.comment-topic}", consumerGroup = "${lili.data.rocketmq.comment-group}") public class CommentMessageListener implements RocketMQListener<MessageExt> { @Autowired private ThumbsUpRecordService thumbsUpRecordService; @Autowired private VideoCommentService videoCommentService; /** * 缓存 */ @Autowired private Cache<Object> cache; @Override public void onMessage(MessageExt messageExt) { try { String msg = new String(messageExt.getBody()); if (StringUtils.isBlank(msg)) { log.error("comment msg is null, cant not consumer"); return; } switch (CommentTagsEnum.valueOf(messageExt.getTags())) { case THUMBS_UP: this.thumbsUp(msg); break; case CANCEL_THUMBS_UP: this.cancelThumbsUp(msg); break; default: log.error("comment msg not match correct tag, consumer err"); break; } } catch (Exception e) { log.error("comment msg consumer err", e); } } /** * 评论点赞 * * @param msg */ public void thumbsUp(String msg) { ThumbsUpRecord record = JSON.parseObject(msg, ThumbsUpRecord.class); videoCommentService.mqThumbsUp(record); } /** * 评论取消点赞 * * @param msg */ public void cancelThumbsUp(String msg) { ThumbsUpRecordForm form = JSON.parseObject(msg, ThumbsUpRecordForm.class); videoCommentService.mqCancelThumbsUp(form); } } consumer/src/main/java/cn/lili/timetask/TimedTaskJobHandler.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/EveryDayExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/EveryHourExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/EveryMinuteExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/broadcast/BroadcastExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/coupon/CouponExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/goods/GoodsExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/hotwords/HotWordsEveryDayTaskExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/order/CancelOrderTaskExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/order/OrderEveryDayTaskExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/order/RechargeOrderTaskExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/PromotionEverydayExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/statistics/MemberStatisticsExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/statistics/OnlineMemberStatistics.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/store/StoreExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/store/StoreRatingExecute.java
File was deleted consumer/src/main/java/cn/lili/timetask/handler/impl/view/PageViewStatisticsExecute.java
File was deleted consumer/src/test/java/cn/lili/buyer/test/cart/MemberStatisticsTest.java
File was deleted framework/src/main/java/cn/lili/common/properties/RocketmqCustomProperties.java
@@ -19,6 +19,12 @@ @ConfigurationProperties(prefix = "lili.data.rocketmq") public class RocketmqCustomProperties { /** * 评论 */ private String commentTopic; private String commentGroup; private String promotionTopic; framework/src/main/java/cn/lili/modules/lmk/constant/RedisKeyExpireConstant.java
New file @@ -0,0 +1,27 @@ package cn.lili.modules.lmk.constant; import java.util.concurrent.TimeUnit; /** * redis key过期时间 * * @author:xp * @date:2025/6/25 10:31 */ public class RedisKeyExpireConstant { /** * 评论数 */ public static final Long COMMENT_NUM_EXPIRE = 15l; /** * 过期时间单位 */ public static final TimeUnit EXPIRE_DAY = TimeUnit.DAYS; // 天 public static final TimeUnit EXPIRE_SED = TimeUnit.SECONDS; // 秒 public static final TimeUnit EXPIRE_HOUR = TimeUnit.HOURS; // 小时 public static final TimeUnit EXPIRE_MINUTES = TimeUnit.MINUTES; // 分钟 } framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoComment.java
@@ -54,6 +54,10 @@ /** 点赞数量 */ private Long thumbsUpNum; @TableField("thumbs_up_job") /** 是否需要定时任务更新点赞数 */ private Boolean thumbsUpJob; @TableField("user_nickname") /** 评论人昵称 */ private String userNickname; framework/src/main/java/cn/lili/modules/lmk/domain/vo/CollectTypeNumVO.java
@@ -10,7 +10,7 @@ public class CollectTypeNumVO { /** * 视频id * id */ private String id; framework/src/main/java/cn/lili/modules/lmk/enums/general/ThumbsUpTypeEnum.java
New file @@ -0,0 +1,45 @@ package cn.lili.modules.lmk.enums.general; import lombok.Getter; import org.apache.commons.lang3.StringUtils; /** * 点赞业务类型 * * @author:xp * @date:2025/5/14 10:30 */ @Getter public enum ThumbsUpTypeEnum { VIDEO_COMMENT("video_comment", "视频评论"), ; private final String value; private final String desc; ThumbsUpTypeEnum(String value, String desc) { this.value = value; this.desc = desc; } /** * 获取含义 * * @param value * @return */ public static String getDescByValue(String value) { if (StringUtils.isBlank(value)) { return null; } for (ThumbsUpTypeEnum e : ThumbsUpTypeEnum.values()){ if (value.equals(e.getValue())) { return e.getDesc(); } } return null; } } framework/src/main/java/cn/lili/modules/lmk/mapper/ThumbsUpRecordMapper.java
@@ -1,6 +1,7 @@ package cn.lili.modules.lmk.mapper; import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; import cn.lili.modules.lmk.domain.vo.CollectTypeNumVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import cn.lili.modules.lmk.domain.vo.ThumbsUpRecordVO; @@ -31,4 +32,10 @@ */ IPage getPage(IPage page, @Param("query") ThumbsUpRecordQuery query); /** * 统计评论点赞数量 * * @return */ List<CollectTypeNumVO> countNumGroupByComment(); } framework/src/main/java/cn/lili/modules/lmk/mapper/VideoCommentMapper.java
@@ -54,4 +54,11 @@ * @return */ List<CollectTypeNumVO> countNumGroupByVideo(); /** * 批量更新视频评论点赞数 * * @param chunk */ void updateCommentThumbsUpNumBatch(@Param("list") List<CollectTypeNumVO> chunk); } framework/src/main/java/cn/lili/modules/lmk/service/ThumbsUpRecordService.java
@@ -4,6 +4,7 @@ import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; import cn.lili.modules.lmk.domain.form.ThumbsUpRecordForm; import cn.lili.modules.lmk.domain.query.ThumbsUpRecordQuery; import cn.lili.modules.lmk.domain.vo.CollectTypeNumVO; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -50,4 +51,10 @@ */ Result all(); /** * 统计评论的点赞数 * * @return */ List<CollectTypeNumVO> countNumGroupByComment(); } framework/src/main/java/cn/lili/modules/lmk/service/VideoCommentService.java
@@ -1,5 +1,6 @@ package cn.lili.modules.lmk.service; 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.domain.vo.CollectTypeNumVO; @@ -82,10 +83,31 @@ Result thumbsUp(ThumbsUpRecordForm form); /** * mq执行点赞评论逻辑 * * @param form */ void mqThumbsUp(ThumbsUpRecord form); /** * 取消点赞评论 * * @param form * @return */ Result cancelThumbsUp(ThumbsUpRecordForm form); /** * mq的取消点赞逻辑 * * @param form */ void mqCancelThumbsUp(ThumbsUpRecordForm form); /** * 批量更新评论点赞数 * * @param numList */ void updateCommentThumbsUpNumBatch(List<CollectTypeNumVO> numList); } framework/src/main/java/cn/lili/modules/lmk/service/impl/ThumbsUpRecordServiceImpl.java
@@ -1,5 +1,6 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.modules.lmk.domain.vo.CollectTypeNumVO; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; import cn.lili.modules.lmk.mapper .ThumbsUpRecordMapper; @@ -88,4 +89,9 @@ .collect(Collectors.toList()); return Result.ok().data(vos); } @Override public List<CollectTypeNumVO> countNumGroupByComment() { return baseMapper.countNumGroupByComment(); } } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoCommentServiceImpl.java
@@ -6,11 +6,16 @@ import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; import cn.lili.common.sensitive.SensitiveWordsFilter; import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; import cn.lili.modules.lmk.domain.entity.ThumbsUpRecord; 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.service.ThumbsUpRecordService; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.CommentTagsEnum; import cn.lili.rocketmq.tags.OrderTagsEnum; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.VideoComment; import cn.lili.modules.lmk.mapper.VideoCommentMapper; @@ -22,7 +27,10 @@ import cn.lili.modules.lmk.domain.form.VideoCommentForm; import cn.lili.modules.lmk.domain.vo.VideoCommentVO; import cn.lili.modules.lmk.domain.query.VideoCommentQuery; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -176,40 +184,75 @@ @Override public Result thumbsUp(ThumbsUpRecordForm form) { boolean exists = new LambdaQueryChainWrapper<>(thumbsUpRecordService.getBaseMapper()) .eq(ThumbsUpRecord::getRefId, form.getRefId()) .eq(ThumbsUpRecord::getUserId, UserContext.getCurrentUserId()) .exists(); if (exists) { return Result.ok(); } ThumbsUpRecord record = ThumbsUpRecordForm.getEntityByForm(form, null); record.setUserId(UserContext.getCurrentUserId()); thumbsUpRecordService.save(record); if (cache.exist(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId()))) { cache.incr(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId())); } else { VideoComment comment = baseMapper.selectById(form.getRefId()); if (Objects.nonNull(comment)) { cache.put(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(comment.getId()), comment.getThumbsUpNum() + 1, EXPIRE_TIME, TimeUnit.DAYS); } } // TODO 使用rocketmq异步写入到mysql中 // rocketMQTemplate.asyncSend(); // 走mq异步处理 String destination = rocketmqCustomProperties.getCommentTopic() + ":" + CommentTagsEnum.THUMBS_UP.name(); rocketMQTemplate.asyncSend(destination, JSON.toJSONString(record), RocketmqSendCallbackBuilder.commonCallback()); return Result.ok(); } @Override @Transactional(rollbackFor = Exception.class) public void mqThumbsUp(ThumbsUpRecord record) { boolean exists = new LambdaQueryChainWrapper<>(thumbsUpRecordService.getBaseMapper()) .eq(ThumbsUpRecord::getRefId, record.getRefId()) .eq(ThumbsUpRecord::getUserId, UserContext.getCurrentUserId()) .exists(); if (exists) { return; } thumbsUpRecordService.save(record); VideoComment comment = this.getById(record.getRefId()); if (cache.exist(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(record.getRefId()))) { 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); } } // 标识该评论需要通过定时任务统计点赞数 if (Objects.nonNull(comment) && ! comment.getThumbsUpJob()) { new LambdaUpdateChainWrapper<>(baseMapper) .eq(VideoComment::getId, comment.getId()) .set(VideoComment::getThumbsUpJob, Boolean.TRUE) .update(); } } @Override public Result cancelThumbsUp(ThumbsUpRecordForm form) { // 走mq异步处理 String destination = rocketmqCustomProperties.getCommentTopic() + ":" + CommentTagsEnum.CANCEL_THUMBS_UP.name(); rocketMQTemplate.asyncSend(destination, JSON.toJSONString(form), RocketmqSendCallbackBuilder.commonCallback()); return Result.ok(); } @Override @Transactional(rollbackFor = Exception.class) public void mqCancelThumbsUp(ThumbsUpRecordForm form) { new LambdaUpdateChainWrapper<>(thumbsUpRecordService.getBaseMapper()) .eq(ThumbsUpRecord::getRefId, form.getRefId()) .eq(ThumbsUpRecord::getThumbsUpType, form.getThumbsUpType()) .eq(ThumbsUpRecord::getUserId, UserContext.getCurrentUserId()) .remove(); // redis数量减一 cache.decr(CachePrefix.VIDEO_COMMENT_LIKE_NUM.getPrefixWithId(form.getRefId())); // TODO mq异步同步到mysql return Result.ok(); 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())); } 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); } } // 标识该评论需要通过定时任务统计点赞数 if (Objects.nonNull(comment) && ! comment.getThumbsUpJob()) { new LambdaUpdateChainWrapper<>(baseMapper) .eq(VideoComment::getId, comment.getId()) .set(VideoComment::getThumbsUpJob, Boolean.TRUE) .update(); } } /** @@ -228,4 +271,18 @@ } return Long.valueOf((Integer) redisNum); } @Override @Transactional(rollbackFor = Exception.class) public void updateCommentThumbsUpNumBatch(List<CollectTypeNumVO> numList) { // 按500条数据进行拆分 List<List<CollectTypeNumVO>> chunks = ListUtils.partition(numList, 500); for (List<CollectTypeNumVO> chunk : chunks) { baseMapper.updateCommentThumbsUpNumBatch(chunk); new LambdaUpdateChainWrapper<>(baseMapper) .in(VideoComment::getId, chunk.stream().map(CollectTypeNumVO::getId).collect(Collectors.toList())) .set(VideoComment::getThumbsUpJob, Boolean.FALSE) .update(); } } } framework/src/main/java/cn/lili/rocketmq/tags/CommentTagsEnum.java
New file @@ -0,0 +1,32 @@ package cn.lili.rocketmq.tags; /** * rocketmq点赞tag * * @author paulG * @since 2020/12/9 **/ public enum CommentTagsEnum { /** * 点赞 */ THUMBS_UP("点赞"), /** * 取消点赞 */ CANCEL_THUMBS_UP("订单状态改变"); private final String description; CommentTagsEnum(String description) { this.description = description; } public String description() { return description; } } framework/src/main/resources/mapper/lmk/ThumbsUpRecordMapper.xml
@@ -41,4 +41,19 @@ LTUR.delete_flag = 0 </select> <select id="countNumGroupByComment" resultType="cn.lili.modules.lmk.domain.vo.CollectTypeNumVO"> SELECT LTUR.ref_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 WHERE LTUR.thumbs_up_type = 'video_comment' AND LTUR.delete_flag = 0 GROUP BY LTUR.ref_id </select> </mapper> framework/src/main/resources/mapper/lmk/VideoCommentMapper.xml
@@ -155,4 +155,19 @@ video_id </select> <update id="updateCommentThumbsUpNumBatch"> UPDATE lmk_video_comment SET thumbs_up_num = CASE id <foreach collection="list" item="comment"> WHEN #{comment.id} THEN #{comment.countNum} </foreach> ELSE thumbs_up_num END WHERE id IN <foreach collection="list" item="comment" open="(" separator="," close=")"> #{comment.id} </foreach> </update> </mapper> lmk-job/src/main/java/cn/lili/job/VideoJob.java
@@ -3,6 +3,7 @@ import cn.lili.modules.lmk.domain.vo.CollectTypeNumVO; import cn.lili.modules.lmk.enums.general.CollectTypeEnum; import cn.lili.modules.lmk.service.MyCollectService; import cn.lili.modules.lmk.service.ThumbsUpRecordService; import cn.lili.modules.lmk.service.VideoCommentService; import cn.lili.modules.lmk.service.VideoService; import com.xxl.job.core.context.XxlJobHelper; @@ -26,6 +27,7 @@ private final VideoService videoService; private final MyCollectService myCollectService; private final VideoCommentService videoCommentService; private final ThumbsUpRecordService thumbsUpRecordService; /** * 视频收藏数统计 @@ -55,4 +57,19 @@ } } /** * 视频评论点赞数统计 * * @throws Exception */ @XxlJob("videoCommentThumbsUpNumJob") public void videoCommentThumbsUpNumJob() throws Exception { XxlJobHelper.log("开始执行:评论点赞数统计"); List<CollectTypeNumVO> numList = thumbsUpRecordService.countNumGroupByComment(); if (CollectionUtils.isNotEmpty(numList)) { videoCommentService.updateCommentThumbsUpNumBatch(numList); } } }