You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot电商项目实时通知实现方案咨询(含WebSocket及替代方案)

基于Spring Boot的电商下单通知实现方案

一、WebSocket 实现步骤

1. 引入依赖

在pom.xml中添加Spring WebSocket依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2. 配置WebSocket

创建配置类注册端点和消息代理:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws-notify")
                .setAllowedOriginPatterns("*")
                .withSockJS();
    }
}

3. 定义消息实体

创建区分买家/商家通知的消息类:

@Data
public class OrderNotifyMessage {
    private String userId;
    private String type; // ORDER_SUCCESS / MERCHANT_DELIVER
    private OrderContent content;

    @Data
    public static class OrderContent {
        private String orderId;
        private List<OrderItem> items;
        private BigDecimal totalAmount;
    }

    @Data
    public static class OrderItem {
        private String productId;
        private String merchantId;
        private Integer quantity;
        private BigDecimal price;
    }
}

4. 客户端连接逻辑

  • 买家端:登录后连接/ws-notify,订阅/queue/order-success-{buyerId}队列接收一对一通知。
  • 商家端:登录后订阅/queue/merchant-deliver-{merchantId}队列,仅接收自身订单通知。

前端JS示例:

const stompClient = new StompJs.Client({
    brokerURL: 'ws://localhost:8080/ws-notify',
    connectHeaders: { 'userId': 'buyer_123' }
});

stompClient.onConnect = (frame) => {
    stompClient.subscribe(`/queue/order-success-buyer_123`, (message) => {
        const notify = JSON.parse(message.body);
        console.log('下单成功:', notify);
        // 前端展示逻辑:弹窗、消息中心等
    });
};

stompClient.activate();

5. 下单时发送通知

在订单服务中完成订单保存后,通过SimpMessagingTemplate推送消息:

@Service
public class OrderService {
    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    public void createOrder(OrderCreateRequest request) {
        // 1. 保存订单到数据库
        Order order = saveOrderToDB(request);
        String buyerId = request.getBuyerId();
        Set<String> merchantIds = order.getItems().stream()
                .map(OrderItem::getMerchantId)
                .collect(Collectors.toSet());

        // 2. 发送买家下单成功通知
        OrderNotifyMessage buyerNotify = buildBuyerNotify(order);
        messagingTemplate.convertAndSendToUser(buyerId, "/queue/order-success", buyerNotify);

        // 3. 批量发送商家待配送通知
        for (String merchantId : merchantIds) {
            OrderNotifyMessage merchantNotify = buildMerchantNotify(order, merchantId);
            messagingTemplate.convertAndSendToUser(merchantId, "/queue/merchant-deliver", merchantNotify);
        }
    }

    // 封装买家/商家通知的工具方法
    private OrderNotifyMessage buildBuyerNotify(Order order) { /* ... */ }
    private OrderNotifyMessage buildMerchantNotify(Order order, String merchantId) { /* ... */ }
}

二、更简便的替代方案:Redis发布订阅 + 长轮询

如果不想维护长连接,可采用该方案:

1. 引入Redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. 下单时发布消息

@Service
public class OrderService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    public void createOrder(OrderCreateRequest request) {
        Order order = saveOrderToDB(request);
        String buyerId = request.getBuyerId();
        Set<String> merchantIds = order.getItems().stream()
                .map(OrderItem::getMerchantId)
                .collect(Collectors.toSet());

        // 发布买家通知到专属频道
        String buyerChannel = String.format("order:success:%s", buyerId);
        redisTemplate.convertAndSend(buyerChannel, JSON.toJSONString(buildBuyerNotify(order)));

        // 发布商家通知到各自专属频道
        for (String merchantId : merchantIds) {
            String merchantChannel = String.format("order:deliver:%s", merchantId);
            redisTemplate.convertAndSend(merchantChannel, JSON.toJSONString(buildMerchantNotify(order, merchantId)));
        }
    }
}

3. 长轮询获取通知

后端提供接口阻塞等待Redis消息,前端定时请求:

@RestController
@RequestMapping("/notify")
public class NotifyController {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/buyer/{buyerId}")
    public ResponseEntity<OrderNotifyMessage> getBuyerNotify(@PathVariable String buyerId) {
        String channel = String.format("order:success:%s", buyerId);
        CountDownLatch latch = new CountDownLatch(1);
        OrderNotifyMessage[] result = new OrderNotifyMessage[1];

        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.subscribe((message, pattern) -> {
            result[0] = JSON.parseObject(new String(message.getBody()), OrderNotifyMessage.class);
            latch.countDown();
        }, channel.getBytes());

        try {
            // 阻塞10秒,超时返回空
            latch.await(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            connection.close();
        }

        return result[0] != null ? ResponseEntity.ok(result[0]) : ResponseEntity.noContent().build();
    }
}

三、方案选择建议

  • WebSocket:适合实时性要求高、用户在线时长稳定的场景(如商家后台),需处理重连和离线消息存储(可结合数据库存未读消息)。
  • Redis发布订阅+长轮询:实现简单,无需维护长连接,适合移动端等用户在线不稳定的场景,实时性略低于WebSocket(取决于轮询间隔)。

内容的提问来源于stack exchange,提问作者Ukeme Elijah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:41:14