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

如何构建可向前端持续推送状态的Java Spring Boot API

实现方案

你需要的是服务端主动推送能力,结合你的技术栈,推荐用Spring WebSocket + STOMP协议实现,复杂度低、生态成熟,完全满足你的需求:


一、后端(Spring Boot)实现

1. 引入依赖

在pom.xml中添加WebSocket启动器:

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

2. 配置WebSocket

新建配置类开启STOMP消息代理,绑定用户标识逻辑:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册WebSocket连接端点,允许React端跨域访问,支持SockJS降级
        registry.addEndpoint("/ws-endpoint")
                .setAllowedOriginPatterns("*") // 生产环境替换为你的React前端域名
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 配置用户级消息的前缀,后续给指定用户发消息时会自动匹配
        registry.setUserDestinationPrefix("/user");
        // 开启内置消息代理,处理队列类消息
        registry.enableSimpleBroker("/queue");
    }

    // 配置握手拦截器,从请求参数中获取user-id绑定到会话Principal
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ChannelInterceptor() {
            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    // 从连接参数中取user-id
                    String userId = accessor.getFirstNativeHeader("user-id");
                    if (userId != null) {
                        // 绑定用户身份到会话
                        accessor.setUser(new UsernamePasswordAuthenticationToken(userId, null, Collections.emptyList()));
                    }
                }
                return message;
            }
        });
    }
}

3. 开发内部状态更新POST接口

提供虚拟机内部调用的更新接口,收到状态后推送给对应用户:

@RestController
@RequestMapping("/api/internal")
public class StatusUpdateController {

    // Spring提供的消息发送工具
    private final SimpMessagingTemplate messagingTemplate;

    public StatusUpdateController(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @PostMapping("/update-status")
    public ResponseEntity<Void> updateUserStatus(@RequestBody StatusUpdateRequest request) {
        // 给指定user-id的用户推送消息,目标订阅路径为 /user/queue/status-updates
        messagingTemplate.convertAndSendToUser(
                request.getUserId(),
                "/queue/status-updates",
                request.getStatusContent()
        );
        return ResponseEntity.ok().build();
    }

    // 请求实体类示例
    public static class StatusUpdateRequest {
        private String userId;
        private Object statusContent;
        // 省略getter、setter
    }
}

注意:该内部接口请务必添加IP白名单校验,只允许你的虚拟机网段访问,避免外部恶意调用


二、前端(React)实现

1. 安装依赖

npm install sockjs-client stompjs

2. 组件内实现连接与订阅逻辑

在需要接收状态更新的React组件中添加如下逻辑:

import { useEffect, useState } from 'react';
import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';

function StatusComponent({ userId }) {
  const [currentStatus, setCurrentStatus] = useState(null);

  useEffect(() => {
    // 初始化STOMP客户端
    const stompClient = new Client({
      webSocketFactory: () => new SockJS('http://你的后端地址/ws-endpoint'),
      connectHeaders: {
        'user-id': userId // 传递当前登录用户的user-id
      },
      onConnect: () => {
        // 订阅当前用户的状态更新队列
        stompClient.subscribe(`/user/queue/status-updates`, (message) => {
          const newStatus = JSON.parse(message.body);
          setCurrentStatus(newStatus);
        });
      },
      onStompError: (frame) => {
        console.error('连接异常', frame);
        // 可在此处添加重连逻辑
      }
    });

    stompClient.activate();

    // 组件销毁时断开连接
    return () => {
      stompClient.deactivate();
    };
  }, [userId]);

  // 渲染状态逻辑省略
  return <div>当前状态:{JSON.stringify(currentStatus)}</div>;
}

export default StatusComponent;

三、验证测试

在虚拟机内部执行curl命令即可触发状态推送:

curl -X POST http://后端地址/api/internal/update-status \
-H "Content-Type: application/json" \
-d '{"userId":"你要推送的用户ID","statusContent":{"orderStatus":"已发货","time":"2024-05-20"}}'

执行后对应user-id的前端页面会自动收到状态更新。


轻量替代方案(SSE)

如果不需要双向通信,也可以用Spring SseEmitter实现,无需额外依赖:

  • 后端维护ConcurrentHashMap<String, List<SseEmitter>>存储每个userId对应的连接实例
  • 前端用EventSource连接后端SSE接口,连接创建时把emitter存入Map
  • 内部POST接口收到更新时,从Map中取出对应userId的所有emitter发送数据
  • 连接断开时从Map中移除对应emitter即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:21:03