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

点赞服务完整消息流转过程详解(原方案,未使用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.xdnf.cn/news/17204.html

相关文章:

  • 学习嵌入式之硬件——ARM体系
  • 昇思+昇腾开发板+DeepSeek模型开发与适配
  • 豆包新模型与PromptPilot工具深度测评:AI应用开发的全流程突破
  • 自然语言处理基础—(1)
  • Java 工具类的“活化石”:Apache Commons 核心用法、性能陷阱与现代替代方案
  • linux-系统性能监控
  • [特殊字符]企业游学 | 探秘字节,解锁AI科技新密码
  • WebSocket 通信与 WebSocketpp 库使用指南
  • Java 大视界 -- 基于 Java 的大数据实时流处理在工业物联网设备故障预测与智能运维中的应用(384)
  • 【STL源码剖析】从源码看 vector:底层扩容逻辑与内存复用机制
  • golang的map
  • 【Linux】重生之从零开始学习运维之主从MGR高可用
  • 【C++】unordered系列容器使用及封装
  • WebStorm转VSCode:高效迁移指南
  • QML开发:QML中的基本元素
  • 项目设计模式草稿纸
  • Docker概述
  • chromedp 笔记
  • Prometheus监控学习-安装
  • LeetCode 112. 路径总和解题思路详解(BFS算法深入理解)
  • pipeline方法关系抽取--课堂笔记
  • SpringBoot AI心理学训练实战
  • 《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线
  • FastAPI快速入门P2:与SpringBoot比较
  • Google AI 发布 MLE-STAR:一款能够自动执行各种 AI 任务的先进机器学习工程代理
  • 使标签垂直水平居中的多种方法
  • C#案例实战
  • 利用Coze平台生成测试用例
  • 基于vscode连接服务器实现远程开发
  • HTML总结全览