SpringBoot实现网页消息推送的5种方法

Spring Boot 实现网页消息推送的 5 种主流方式(2025–2026 实战指南)

网页消息推送(实时通知、聊天、状态更新、订单提醒等)是现代 Web 应用的核心功能之一。Spring Boot 提供了非常成熟的支持,下面整理出目前最常用、最实用的 5 种实现方式,从简单到高级排序,并标注适用场景、优缺点和核心代码要点。

1. 短轮询(Short Polling) + Ajax / Fetch

原理:前端定时(每 3–10 秒)通过 Ajax / Fetch 向后端拉取新消息。

适用场景:对实时性要求不高、开发周期短、兼容性极强

优点:实现最简单,无需额外依赖,兼容所有浏览器
缺点:服务器压力大(大量无效请求)、延迟高、不够“实时”

核心代码(后端)

@RestController
public class NotificationController {

    @GetMapping("/notifications")
    public ResponseEntity<List<String>> getNotifications() {
        // 查询是否有新消息(数据库 / Redis / 内存队列)
        List<String> newMsgs = notificationService.pollNewMessages();
        return ResponseEntity.ok(newMsgs);
    }
}

前端(Vue/React 通用):

setInterval(async () => {
  const res = await fetch('/notifications');
  const data = await res.json();
  if (data.length > 0) addNotifications(data);
}, 5000);

2. 长轮询(Long Polling)

原理:客户端发起请求,后端如果没有新消息就挂起请求(不返回),有新消息立即返回;前端收到后立即再发起下一次请求。

适用场景:实时性要求较高,但不想引入 WebSocket/SSE

优点:比短轮询节省资源,实现相对简单
缺点:连接频繁建立/断开,服务器需维护大量长连接

后端实现(使用 DeferredResult):

@GetMapping("/long-poll")
public DeferredResult<List<String>> longPoll() {
    DeferredResult<List<String>> result = new DeferredResult<>(30000L); // 30秒超时

    // 异步监听新消息(可使用消息队列或 BlockingQueue)
    messageQueue.addListener(msg -> {
        if (!result.isSetOrExpired()) {
            result.setResult(Collections.singletonList(msg));
        }
    });

    result.onTimeout(() -> result.setResult(Collections.emptyList()));
    return result;
}

3. Server-Sent Events(SSE)

原理:基于 HTTP 的单向服务器推送,客户端使用 EventSource 建立持久连接,服务端通过 text/event-stream 推送事件。

适用场景:服务器 → 客户端单向推送(如通知、进度、股票价格、日志监控)

优点:实现简单、自动重连、基于标准 HTTP、资源消耗比 WebSocket 低
缺点:单向(客户端不能主动发消息)、不支持二进制

后端核心代码(Spring Boot 推荐方式):

@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> sseNotifications() {
    return Flux.interval(Duration.ofSeconds(1))
               .map(seq -> ServerSentEvent.<String>builder()
                   .id(String.valueOf(seq))
                   .event("message")
                   .data("服务器推送:" + LocalDateTime.now())
                   .build());
}

或使用 SseEmitter(更灵活,支持断开重连)

@GetMapping("/notifications")
public SseEmitter stream() {
    SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
    // 在其他地方调用 emitter.send() 推送
    return emitter;
}

前端

const source = new EventSource('/sse');
source.onmessage = e => console.log('收到:', e.data);

4. WebSocket(原生 / @ServerEndpoint)

原理:全双工通信通道,浏览器和服务器建立持久 TCP 连接。

适用场景:需要双向实时通信(聊天、协作编辑、游戏)

优点:真正的实时双向、低延迟
缺点:实现稍复杂、需处理断线重连、心跳

Spring Boot 简单实现

@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketEndpoint {

    private static final Map<String, Session> sessions = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        sessions.put(userId, session);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // 广播或点对点
    }

    public static void sendToUser(String userId, String msg) {
        Session session = sessions.get(userId);
        if (session != null && session.isOpen()) {
            session.getAsyncRemote().sendText(msg);
        }
    }
}

配置

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/my-ws").setAllowedOrigins("*");
    }
}

5. WebSocket + STOMP(最推荐的生产方式)

原理:在 WebSocket 上层使用 STOMP 协议(类似 HTTP 的消息协议),支持订阅主题、点对点、广播等。

适用场景:几乎所有中大型实时应用(聊天、通知、实时仪表盘、订单状态)

优点:功能强大(订阅/取消订阅、断线重连、消息确认)、易于管理用户会话、支持广播/点对点

依赖

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

配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue"); // 订阅前缀
        config.setApplicationDestinationPrefixes("/app"); // 发送前缀
        config.setUserDestinationPrefix("/user"); // 点对点前缀
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOriginPatterns("*")
                .withSockJS(); // 支持降级
    }
}

发送消息(广播):

@Autowired
private SimpMessagingTemplate messagingTemplate;

public void sendNotification(String message) {
    messagingTemplate.convertAndSend("/topic/notifications", message);
}

点对点(需结合 Spring Security 或自定义 Principal):

messagingTemplate.convertAndSendToUser(username, "/queue/notifications", message);

前端(使用 stomp.js 或 @stomp/stompjs):

const client = new Client({
  brokerURL: 'ws://localhost:8080/ws',
  onConnect: () => {
    client.subscribe('/topic/notifications', msg => console.log(msg.body));
    client.subscribe('/user/queue/notifications', msg => console.log(msg.body));
  }
});
client.activate();

总结对比表

方式实时性方向性复杂度资源消耗推荐场景
短轮询★☆☆☆☆双向最低原型、兼容性要求极高
长轮询★★☆☆☆双向中等实时性
SSE★★★★☆服务器→客户端服务器单向推送首选
原生 WebSocket★★★★★双向简单双向场景
WebSocket + STOMP★★★★★双向中高生产级实时应用首选

2026 年推荐优先级
大多数场景 → WebSocket + STOMP
纯服务器推送、资源敏感 → SSE
简单/原型 → 轮询

你现在项目里想实现哪种推送?是聊天、通知、进度条还是其他?可以告诉我具体需求,我可以给出更详细的代码和配置。

文章已创建 4543

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部