# WebSocket 集成说明 ## 概述 在将商户店铺入住申请接口从 `alien-store` 迁移到 `alien-store-platform` 的过程中,需要集成 WebSocket 消息推送功能,用于实时通知商户申请已受理。 ## 当前状态 ### 已完成 - ✅ 在 `StoreManageServiceImpl.sendApplicationNotice()` 中添加了 WebSocket 消息推送的调用逻辑 - ✅ 创建了 `WebSocketUtil` 工具类作为占位实现 - ✅ 保存通知消息到数据库(`LifeNotice` 表) - ✅ 构建了符合规范的 `WebSocketVo` 对象 ### 待完成 - ⚠️ WebSocket 实际消息推送功能(当前仅记录日志) ## 问题说明 ### 架构限制 `alien-store` 模块中的 `WebSocketProcess` 类位于 `shop.alien.store.config` 包下,`alien-store-platform` 模块无法直接引用: ```java // alien-store 中的 WebSocketProcess @ServerEndpoint(value = "/socket/{sendId}") public class WebSocketProcess { public void sendMessage(String id, String message) throws Exception { // WebSocket 发送逻辑 } } ``` ### 技术原因 - **模块隔离**:`alien-store-platform` 和 `alien-store` 是独立的微服务模块 - **依赖管理**:`alien-store-platform` 的 pom.xml 中未引入 `alien-store` 依赖 - **架构设计**:微服务间不应直接引用对方的实现类 ## 解决方案 ### 方案 1:将 WebSocketProcess 移到共享模块(推荐)⭐ **步骤:** 1. 将 `WebSocketProcess.java` 从 `alien-store` 移动到 `alien-config` 模块 2. 修改包路径为 `shop.alien.config.websocket.WebSocketProcess` 3. 在 `alien-store` 和 `alien-store-platform` 的 `pom.xml` 中都引用 `alien-config` 依赖(已存在) 4. 更新 `WebSocketUtil` 使用共享的 `WebSocketProcess` **优点:** - ✅ 代码复用,统一管理 - ✅ 符合微服务架构设计原则 - ✅ 两个服务都可以使用相同的 WebSocket 功能 **缺点:** - ❌ 需要重构 `alien-store` 中的现有代码 - ❌ 可能影响到其他使用 WebSocket 的功能 **实现示例:** ```java // alien-config/src/main/java/shop/alien/config/websocket/WebSocketProcess.java package shop.alien.config.websocket; @Slf4j @Component @ServerEndpoint(value = "/socket/{sendId}") public class WebSocketProcess { // ... 原有实现保持不变 } // alien-store-platform/.../WebSocketUtil.java package shop.alien.storeplatform.util; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import shop.alien.config.websocket.WebSocketProcess; @Component @RequiredArgsConstructor public class WebSocketUtil { private final WebSocketProcess webSocketProcess; public void sendMessage(String receiverId, String message) { webSocketProcess.sendMessage(receiverId, message); } } ``` --- ### 方案 2:通过消息队列异步推送 **步骤:** 1. 引入消息队列(RabbitMQ 或 Kafka) 2. `alien-store-platform` 发送消息到 MQ 3. `alien-store` 消费 MQ 消息并通过 WebSocket 推送 **优点:** - ✅ 服务解耦,符合微服务架构 - ✅ 异步处理,不影响业务主流程 - ✅ 支持消息持久化和重试机制 **缺点:** - ❌ 增加系统复杂度 - ❌ 需要引入和维护消息队列中间件 - ❌ 消息推送存在延迟 **实现示例:** ```java // alien-store-platform - 生产者 @Component @RequiredArgsConstructor public class WebSocketUtil { private final RabbitTemplate rabbitTemplate; public void sendMessage(String receiverId, String message) { WebSocketMessage msg = new WebSocketMessage(receiverId, message); rabbitTemplate.convertAndSend("websocket.exchange", "websocket.route", msg); } } // alien-store - 消费者 @Component @RequiredArgsConstructor public class WebSocketMessageConsumer { private final WebSocketProcess webSocketProcess; @RabbitListener(queues = "websocket.queue") public void handleMessage(WebSocketMessage msg) { webSocketProcess.sendMessage(msg.getReceiverId(), msg.getMessage()); } } ``` --- ### 方案 3:通过 Feign 调用 REST 接口 **步骤:** 1. 在 `alien-store` 中创建 WebSocket 发送的 REST 接口 2. 在 `alien-api` 中定义 Feign 客户端接口 3. `alien-store-platform` 通过 Feign 调用 **优点:** - ✅ 实现简单直接 - ✅ 无需额外中间件 - ✅ 易于调试和监控 **缺点:** - ❌ 增加 HTTP 调用开销 - ❌ 存在网络延迟 - ❌ 需要处理服务间调用失败的情况 **实现示例:** ```java // alien-store - 提供 REST 接口 @RestController @RequestMapping("/internal/websocket") public class WebSocketInternalController { @Autowired private WebSocketProcess webSocketProcess; @PostMapping("/sendMessage") public R sendMessage(@RequestParam String receiverId, @RequestParam String message) { webSocketProcess.sendMessage(receiverId, message); return R.success(); } } // alien-api - Feign 客户端 @FeignClient(name = "alien-store", path = "/internal/websocket") public interface WebSocketFeignClient { @PostMapping("/sendMessage") R sendMessage(@RequestParam("receiverId") String receiverId, @RequestParam("message") String message); } // alien-store-platform - 使用 Feign @Component @RequiredArgsConstructor public class WebSocketUtil { private final WebSocketFeignClient webSocketFeignClient; public void sendMessage(String receiverId, String message) { webSocketFeignClient.sendMessage(receiverId, message); } } ``` --- ## 当前实现 ### WebSocketUtil(占位实现) `alien-store-platform/src/main/java/shop/alien/storeplatform/util/WebSocketUtil.java` ```java @Slf4j @Component public class WebSocketUtil { public void sendMessage(String receiverId, String message) { // TODO: 实现WebSocket消息推送 log.info("WebSocketUtil.sendMessage - [占位实现] 准备发送消息: receiverId={}, message={}", receiverId, message); log.warn("WebSocketUtil.sendMessage - WebSocket功能未完全实现,消息未实际推送"); } } ``` ### 调用位置 `alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StoreManageServiceImpl.java` ```java private void sendApplicationNotice(String userAccount) { // ... 构建通知消息 // 1. 保存通知消息到数据库 lifeNoticeMapper.insert(lifeNotice); // 2. 通过 WebSocket 实时推送消息 WebSocketVo websocketVo = new WebSocketVo(); websocketVo.setSenderId("system"); websocketVo.setReceiverId(receiverId); websocketVo.setCategory("notice"); websocketVo.setNoticeType("1"); websocketVo.setIsRead(0); websocketVo.setText(JSONObject.from(lifeNotice).toJSONString()); try { webSocketUtil.sendMessage(receiverId, JSONObject.from(websocketVo).toJSONString()); log.info("WebSocket消息推送成功: receiverId={}", receiverId); } catch (Exception e) { log.error("WebSocket消息推送失败: {}", e.getMessage(), e); } } ``` ## 推荐实施步骤 ### 短期方案(快速上线) 采用 **方案 3:Feign 调用** 1. 在 `alien-store` 中添加 WebSocket 发送的内部接口 2. 在 `alien-api` 中定义 Feign 客户端 3. 更新 `alien-store-platform` 的 `WebSocketUtil` 4. 测试验证 **预计时间:** 1-2 小时 ### 长期方案(架构优化) 采用 **方案 1:共享模块** 1. 创建 `alien-config` 的 `websocket` 子包 2. 迁移 `WebSocketProcess` 到共享模块 3. 更新 `alien-store` 和 `alien-store-platform` 的引用 4. 全面回归测试 **预计时间:** 4-8 小时 ## 测试验证 ### 功能测试 1. 调用 `/storeManage/applyStore` 接口提交店铺入住申请 2. 检查数据库 `life_notice` 表是否插入通知记录 3. 检查 WebSocket 客户端是否收到实时消息 4. 验证消息内容格式和字段完整性 ### 日志验证 ```log [INFO ] WebSocketUtil.sendMessage - [占位实现] 准备发送消息: receiverId=store_13800138000 [WARN ] WebSocketUtil.sendMessage - WebSocket功能未完全实现,消息未实际推送 ``` ## 相关文件 - `alien-store-platform/src/main/java/shop/alien/storeplatform/util/WebSocketUtil.java` - `alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StoreManageServiceImpl.java` - `alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java` - `alien-entity/src/main/java/shop/alien/entity/store/vo/WebSocketVo.java` - `alien-entity/src/main/java/shop/alien/entity/store/LifeNotice.java` ## 注意事项 1. ⚠️ **通知已保存到数据库**:即使 WebSocket 推送失败,通知消息也已保存到 `life_notice` 表,用户可以在消息列表中查看 2. ⚠️ **异常处理**:当前实现已捕获 WebSocket 推送异常,不会影响主业务流程 3. ⚠️ **日志记录**:占位实现会记录警告日志,便于后续排查和优化 4. ⚠️ **兼容性**:选择方案 1 时需要确保不影响 `alien-store` 现有的 WebSocket 功能 ## 更新记录 - 2025-01-xx:初始创建,添加 WebSocket 占位实现 - 待定:实施正式的 WebSocket 推送方案