SpringBoot實現(xiàn)網(wǎng)頁消息推送的5種方法對比
網(wǎng)頁消息推送(實時通知、聊天、狀態(tài)更新、訂單提醒等)是現(xiàn)代 Web 應(yīng)用的核心功能之一。Spring Boot 提供了非常成熟的支持,下面整理出目前最常用、最實用的 5 種實現(xiàn)方式,從簡單到高級排序,并標注適用場景、優(yōu)缺點和核心代碼要點。
1. 短輪詢(Short Polling) + Ajax / Fetch
原理:前端定時(每 3–10 秒)通過 Ajax / Fetch 向后端拉取新消息。
適用場景:對實時性要求不高、開發(fā)周期短、兼容性極強
優(yōu)點:實現(xiàn)最簡單,無需額外依賴,兼容所有瀏覽器
缺點:服務(wù)器壓力大(大量無效請求)、延遲高、不夠“實時”
核心代碼(后端):
@RestController
public class NotificationController {
@GetMapping("/notifications")
public ResponseEntity<List<String>> getNotifications() {
// 查詢是否有新消息(數(shù)據(jù)庫 / Redis / 內(nèi)存隊列)
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)
原理:客戶端發(fā)起請求,后端如果沒有新消息就掛起請求(不返回),有新消息立即返回;前端收到后立即再發(fā)起下一次請求。
適用場景:實時性要求較高,但不想引入 WebSocket/SSE
優(yōu)點:比短輪詢節(jié)省資源,實現(xiàn)相對簡單
缺點:連接頻繁建立/斷開,服務(wù)器需維護大量長連接
后端實現(xiàn)(使用 DeferredResult):
@GetMapping("/long-poll")
public DeferredResult<List<String>> longPoll() {
DeferredResult<List<String>> result = new DeferredResult<>(30000L); // 30秒超時
// 異步監(jiān)聽新消息(可使用消息隊列或 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 的單向服務(wù)器推送,客戶端使用 EventSource 建立持久連接,服務(wù)端通過 text/event-stream 推送事件。
適用場景:服務(wù)器 → 客戶端單向推送(如通知、進度、股票價格、日志監(jiān)控)
優(yōu)點:實現(xiàn)簡單、自動重連、基于標準 HTTP、資源消耗比 WebSocket 低
缺點:單向(客戶端不能主動發(fā)消息)、不支持二進制
后端核心代碼(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("服務(wù)器推送:" + LocalDateTime.now())
.build());
}
或使用 SseEmitter(更靈活,支持斷開重連):
@GetMapping("/notifications")
public SseEmitter stream() {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
// 在其他地方調(diào)用 emitter.send() 推送
return emitter;
}
前端:
const source = new EventSource('/sse');
source.onmessage = e => console.log('收到:', e.data);
4. WebSocket(原生 / @ServerEndpoint)
原理:全雙工通信通道,瀏覽器和服務(wù)器建立持久 TCP 連接。
適用場景:需要雙向?qū)崟r通信(聊天、協(xié)作編輯、游戲)
優(yōu)點:真正的實時雙向、低延遲
缺點:實現(xiàn)稍復(fù)雜、需處理斷線重連、心跳
Spring Boot 簡單實現(xiàn):
@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(最推薦的生產(chǎn)方式)
原理:在 WebSocket 上層使用 STOMP 協(xié)議(類似 HTTP 的消息協(xié)議),支持訂閱主題、點對點、廣播等。
適用場景:幾乎所有中大型實時應(yīng)用(聊天、通知、實時儀表盤、訂單狀態(tài))
優(yōu)點:功能強大(訂閱/取消訂閱、斷線重連、消息確認)、易于管理用戶會話、支持廣播/點對點
依賴:
<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"); // 發(fā)送前綴
config.setUserDestinationPrefix("/user"); // 點對點前綴
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
.withSockJS(); // 支持降級
}
}
發(fā)送消息(廣播):
@Autowired
private SimpMessagingTemplate messagingTemplate;
public void sendNotification(String message) {
messagingTemplate.convertAndSend("/topic/notifications", message);
}
點對點(需結(jié)合 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();
總結(jié)對比表
| 方式 | 實時性 | 方向性 | 復(fù)雜度 | 資源消耗 | 推薦場景 |
|---|---|---|---|---|---|
| 短輪詢 | ★☆☆☆☆ | 雙向 | 最低 | 高 | 原型、兼容性要求極高 |
| 長輪詢 | ★★☆☆☆ | 雙向 | 低 | 中 | 中等實時性 |
| SSE | ★★★★☆ | 服務(wù)器→客戶端 | 低 | 低 | 服務(wù)器單向推送首選 |
| 原生 WebSocket | ★★★★★ | 雙向 | 中 | 中 | 簡單雙向場景 |
| WebSocket + STOMP | ★★★★★ | 雙向 | 中高 | 中 | 生產(chǎn)級實時應(yīng)用首選 |
2026 年推薦優(yōu)先級:
- 大多數(shù)場景 → WebSocket + STOMP
- 純服務(wù)器推送、資源敏感 → SSE
- 簡單/原型 → 輪詢
到此這篇關(guān)于SpringBoot實現(xiàn)網(wǎng)頁消息推送的5種方法對比的文章就介紹到這了,更多相關(guān)SpringBoot網(wǎng)頁消息推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot使用Prometheus實現(xiàn)監(jiān)控
在當今的軟件開發(fā)世界中,監(jiān)控是至關(guān)重要的一部分,本文主要介紹了如何在Spring Boot應(yīng)用程序中使用Prometheus進行監(jiān)控,以幫助大家更好地理解和管理您的應(yīng)用程序,有需要的可以參考下2023-10-10
spring整合redis實現(xiàn)數(shù)據(jù)緩存的實例代碼
這篇文章主要介紹了spring整合redis實現(xiàn)數(shù)據(jù)緩存,需要的朋友可以參考下2018-09-09
Spring里的Async注解實現(xiàn)異步操作的方法步驟
這篇文章主要介紹了Spring里的Async注解實現(xiàn)異步操作的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
如何在mapper文件中使用in("str1","str2")
這篇文章主要介紹了如何在mapper文件中使用in("str1","str2"),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

