当前位置: 首页 > news >正文

点赞服务完整消息流转过程详解(原方案,未使用Redis)

第一步:用户发起点赞请求

用户在前端点击点赞按钮,会向后端发送POST请求:

POST /likes
Content-Type: application/json{"bizId": 1001,"bizType": "QA","liked": true
}


对应Controller代码:

@PostMapping
public void addLikeRecord(@Valid @RequestBody LikeRecordFormDTO recordFormDTO){likedRecordService.addLikeRecord(recordFormDTO);
}
@Data
@ApiModel(description = "点赞记录表单实体")
public class LikeRecordFormDTO {@ApiModelProperty("点赞业务id")@NotNull(message = "业务id不能为空")private Long bizId;@ApiModelProperty("点赞业务类型")@NotNull(message = "业务类型不能为空")private String bizType;@ApiModelProperty("是否点赞,true:点赞;false:取消点赞")@NotNull(message = "是否点赞不能为空")private Boolean liked;
}


 第二步:处理点赞业务逻辑

Controller调用服务层处理点赞请求:

@Override
public void addLikeRecord(LikeRecordFormDTO recordFormDTO) {Long userId = UserContext.getUser();// 判断是点赞还是取消点赞boolean result = recordFormDTO.getLiked();boolean success;if(result){success = like(recordFormDTO);      // 点赞操作}else{success = unlike(recordFormDTO);   // 取消点赞操作}// 判断是否执行成功,失败直接结束if(!success){return;}// 统计最新的点赞次数Integer count = this.lambdaQuery().eq(LikedRecord::getBizId, recordFormDTO.getBizId()).count();// 发送MQ通知mqHelper.send(LIKE_RECORD_EXCHANGE,                           // 交换机: "like.record.topic"StringUtils.format(LIKED_TIMES_KEY_TEMPLATE,recordFormDTO.getBizType()),  // 路由键: "QA.times.changed"LikedTimesDTO.of(recordFormDTO.getBizId(), count) // 消息内容);
}


第三步:执行点赞操作

private boolean like(LikeRecordFormDTO recordFormDTO) {Long userId = UserContext.getUser();// 先检查是否点赞过Integer count = this.lambdaQuery().eq(LikedRecord::getUserId, userId).eq(LikedRecord::getBizId, recordFormDTO.getBizId()).count();// 点赞过直接结束if(count > 0){return false;}// 没有点赞过则新增点赞记录LikedRecord record = new LikedRecord();record.setUserId(userId);record.setBizId(recordFormDTO.getBizId());record.setBizType(recordFormDTO.getBizType());record.setCreateTime(LocalDateTime.now());record.setUpdateTime(LocalDateTime.now());boolean save = this.save(record);return save;
}

第四步:统计点赞次数并发送消息

在点赞操作成功后,统计该业务ID的总点赞数,并通过[RabbitMqHelper]发送消息:

public <T> void send(String exchange, String routingKey, T t) {log.debug("准备发送消息,exchange:{}, RoutingKey:{}, message:{}", exchange, routingKey, t);// 1.设置消息标示,用于消息确认String id = UUID.randomUUID().toString(true);CorrelationData correlationData = new CorrelationData(id);// 2.设置发送超时时间为500毫秒rabbitTemplate.setReplyTimeout(500);// 3.发送消息,同时设置消息idrabbitTemplate.convertAndSend(exchange, routingKey, t, processor, correlationData);
}


@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")
public class LikedTimesDTO {private Long bizId;        // 业务ID(评论ID)private Integer likedTimes; // 点赞次数
}

第五步:RabbitMQ路由消息

RabbitMQ接收到消息后,根据交换机类型(topic)和路由键(QA.times.changed)将消息路由到绑定的队列。

在学习服务中,我们有如下监听器配置:

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "qa.liked.times.queue", durable = "true"),     // 队列exchange = @Exchange(name = LIKE_RECORD_EXCHANGE, type = ExchangeTypes.TOPIC), // 交换机key = QA_LIKED_TIMES_KEY                                             // 路由键: "QA.times.changed"
))
public void listenReplyLikedTimesChange(LikedTimesDTO dto){log.debug("监听到回答或评论{}的点赞数变更:{}", dto.getBizId(), dto.getLikedTimes());// 更新数据库中对应记录的点赞次数InteractionReply r = new InteractionReply();r.setId(dto.getBizId());r.setLikedTimes(dto.getLikedTimes());replyService.updateById(r);
}

第六步:学习服务接收并处理消息

当学习服务接收到消息后,执行以下操作:

1. 日志记录:`log.debug("监听到回答或评论{}的点赞数变更:{}", dto.getBizId(), dto.getLikedTimes());`

2. 更新数据库:

InteractionReply r = new InteractionReply();
r.setId(dto.getBizId());           // 设置评论ID
r.setLikedTimes(dto.getLikedTimes()); // 设置新的点赞次数
replyService.updateById(r);        // 更新数据库记录
@Data
@TableName("interaction_reply")
@ApiModel(value="InteractionReply对象", description="互动问题的回答或评论")
public class InteractionReply implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "互动问题的回答id")@TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;// ... 其他字段@ApiModelProperty(value = "点赞数量")private Integer likedTimes;  // 点赞次数字段// ... 其他字段
}

第七步:前端展示更新后的点赞数

当用户再次查询评论列表时,可以直接从数据库中获取最新的点赞数,而不需要实时统计

// InteractionReplyServiceImpl.java 中查询回复列表的部分代码
Page<InteractionReply> page = this.lambdaQuery()// ... 查询条件.page(query.toMpPage(/*排序条件*/));// 返回的InteractionReply对象中likedTimes字段已经是最新值


完整流程图


[用户点击点赞]

[前端发送HTTP请求 → POST /likes]

[Controller接收请求 → LikedRecordController.addLikeRecord()]

[Service处理业务 → LikedRecordServiceImpl.addLikeRecord()]

[执行点赞操作 → like() 或 unlike()]

[统计点赞总数 → lambdaQuery().count()]

[发送MQ消息 → RabbitMqHelper.send()]

[RabbitMQ路由消息]

[学习服务接收消息 → LikeTimesChangeListener.listenReplyLikedTimesChange()]

[更新数据库 → replyService.updateById()]

[用户查询时直接获取最新点赞数]

 总结

这个消息流转过程的关键优势:

1. 解耦合:点赞服务和学习服务通过消息队列解耦,不需要直接调用对方接口
2. 异步处理:点赞操作不需要等待数据库更新完成,提高响应速度
3. 最终一致性:通过消息机制保证点赞数在各个服务间最终一致
4. 可靠性:使用持久化队列和消息确认机制,确保消息不丢失
5. 扩展性:可以轻松增加其他服务监听相同的点赞事件

这就是整个点赞服务的消息流转过程,从用户操作到数据更新的完整链路。

http://www.lryc.cn/news/612237.html

相关文章:

  • 数据仓库命名规范
  • TypeScript 数组类型精简知识点
  • 【后端】java 抽象类和接口的介绍和区别
  • Unity打造塔科夫式网格背包系统
  • Enhancing Long Video Question Answering with Scene-Localized Frame Grouping
  • 根据经纬度(从nc格式环境数据文件中)提取环境因子
  • 基于Hadoop的股票大数据分析可视化及多模型的股票预测研究与实现
  • 2025年测绘程序设计模拟赛一--地形图图幅编号及图廓点经纬度计算
  • DAY32打卡
  • golang的map
  • 哈尔滨云前沿-关于物理服务器
  • 关于 idea 里 properties 文件的中文乱码问题
  • get请求中文字符参数乱码问题
  • 软件定义汽车 --- 电子电气架构的驱动
  • Vue Vant使用
  • AI大语言模型如何重塑软件开发与测试流程
  • 初识神经网络01——认识PyTorch
  • 需求EAV模型的优化与思考
  • PCL 平面特征点提取
  • 一、Istio基础学习
  • Next.js 服务器组件与客户端组件:区别解析
  • [FOC电机控制]-高速刹车机制
  • 滑动窗口相关题目
  • C++ 运算符重载:避免隐式类型转换的艺术
  • 利用DeepSeek编写go语言按行排序程序
  • DAY 37 早停策略和模型权重的保存
  • 线程互斥与同步
  • 周鸿祎:AI 时代安全智能体,能否重塑数字安全格局?
  • 一个AI硬件项目经理的PMP实战笔记
  • OpenObserve非sql模式 query editor 中 xx like ‘|’报错如何处理