Springboot?實(shí)現(xiàn)Server-Sent?Events的項(xiàng)目實(shí)踐
在 Spring Boot 中,返回 text/event-stream
類(lèi)型的響應(yīng)通常用于實(shí)現(xiàn) Server-Sent Events (SSE),這種方式允許服務(wù)器推送實(shí)時(shí)更新到瀏覽器??蛻舳送ㄟ^(guò) EventSource
API 監(jiān)聽(tīng)并接收這些事件。Spring Boot 可以通過(guò)使用 @RestController
和 SseEmitter
來(lái)實(shí)現(xiàn)這一功能。
步驟 1:創(chuàng)建 SSE Controller 返回 text/event-stream
我們可以通過(guò) @GetMapping
來(lái)創(chuàng)建一個(gè) API,返回 text/event-stream
類(lèi)型的數(shù)據(jù)。這個(gè)數(shù)據(jù)會(huì)是一個(gè)持續(xù)的流,瀏覽器會(huì)實(shí)時(shí)地接收它。
示例:通過(guò) Spring Boot 返回 text/event-stream 類(lèi)型的響應(yīng)
- 控制器:在 Spring Boot 中定義一個(gè)返回
text/event-stream
類(lèi)型的 API 接口。 - 使用
SseEmitter
:SseEmitter
是 Spring 提供的一個(gè)類(lèi),用于處理 Server-Sent Events 流。我們可以利用它來(lái)異步地向客戶端推送數(shù)據(jù)。
示例 1:簡(jiǎn)單的 SSE 實(shí)現(xiàn)
在這個(gè)示例中,我們將創(chuàng)建一個(gè)簡(jiǎn)單的 Spring Boot 控制器,該控制器將返回一個(gè)實(shí)時(shí)的事件流(SSE)。
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RestController public class SseController { /** * 這個(gè)接口會(huì)返回一個(gè)持續(xù)的事件流,瀏覽器會(huì)通過(guò) EventSource 接收 */ @GetMapping("/sse") public SseEmitter handleSse() { SseEmitter emitter = new SseEmitter(); // 啟動(dòng)一個(gè)新的線程模擬定期推送事件 new Thread(() -> { try { for (int i = 0; i < 10; i++) { // 向客戶端發(fā)送數(shù)據(jù) emitter.send("data: Event " + i + "\n\n"); Thread.sleep(1000); // 每秒發(fā)送一次 } emitter.complete(); // 發(fā)送完畢后,標(biāo)記事件流完成 } catch (Exception e) { emitter.completeWithError(e); // 如果出現(xiàn)異常,標(biāo)記事件流出錯(cuò) } }).start(); return emitter; // 返回 SseEmitter 實(shí)例,它會(huì)處理異步流式數(shù)據(jù) } }
說(shuō)明:
SseEmitter
用于處理 SSE 連接。我們將數(shù)據(jù)通過(guò)emitter.send()
發(fā)送到客戶端。- 事件通過(guò)
data: <message>
格式發(fā)送給客戶端,注意每條消息以兩個(gè)換行符結(jié)束(\n\n
)。 Thread.sleep(1000)
用于模擬每秒發(fā)送一個(gè)事件。如果你需要定期發(fā)送事件,可以通過(guò)類(lèi)似的機(jī)制來(lái)實(shí)現(xiàn)。- 最后,通過(guò)
emitter.complete()
標(biāo)記事件流結(jié)束。如果發(fā)生錯(cuò)誤,則使用emitter.completeWithError()
。
步驟 2:前端接收 SSE 事件
在前端,使用 JavaScript 的 EventSource
API 接收服務(wù)器推送的事件。這個(gè) API 會(huì)保持與服務(wù)器的連接,一旦有新的事件,瀏覽器會(huì)自動(dòng)處理。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Server-Sent Events Example</title> </head> <body> <h1>Server-Sent Events Example</h1> <div id="messages"></div> <script> // 創(chuàng)建一個(gè) EventSource 對(duì)象,連接到 /sse 接口 const eventSource = new EventSource("/sse"); // 每當(dāng)接收到數(shù)據(jù)時(shí),處理該事件 eventSource.onmessage = function(event) { const messagesDiv = document.getElementById('messages'); const message = document.createElement('p'); message.textContent = event.data; messagesDiv.appendChild(message); }; // 錯(cuò)誤處理 eventSource.onerror = function(error) { console.error("EventSource failed:", error); }; </script> </body> </html>
步驟 3:配置 Spring Boot 啟用異步支持
SSE 通常需要異步處理,因此在 Spring Boot 中啟用異步支持是非常重要的??梢酝ㄟ^(guò) @EnableAsync
來(lái)啟用異步支持。
啟用異步支持
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; @Configuration @EnableAsync public class AsyncConfig { }
步驟 4:定時(shí)推送數(shù)據(jù)(可選)
如果你希望定期推送事件(例如,每隔一定時(shí)間推送一個(gè)消息),可以使用 Spring 的 @Scheduled
注解來(lái)安排定時(shí)任務(wù)。
示例:定時(shí)發(fā)送事件
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Controller; @Controller public class ScheduledSseController { private final SseEmitter emitter = new SseEmitter(); @Scheduled(fixedRate = 5000) // 每5秒發(fā)送一個(gè)事件 public void sendScheduledEvent() { try { emitter.send("data: Scheduled Event at " + System.currentTimeMillis() + "\n\n"); } catch (IOException e) { emitter.completeWithError(e); } } }
在上面的示例中,@Scheduled(fixedRate = 5000)
會(huì)定期每 5 秒發(fā)送一次事件。
步驟 5:處理多客戶端連接
如果你需要管理多個(gè)客戶端連接,可以將 SseEmitter
實(shí)例存儲(chǔ)在一個(gè)列表中,并為每個(gè)連接發(fā)送事件。每當(dāng)有新事件時(shí),你可以通過(guò)遍歷這些連接,發(fā)送事件到所有連接的客戶端。
import org.springframework.stereotype.Controller; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.bind.annotation.GetMapping; import java.io.IOException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @Controller public class MultiClientSseController { private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>(); @GetMapping("/sse") public SseEmitter handleSse() { SseEmitter emitter = new SseEmitter(); emitters.add(emitter); // 在新線程中發(fā)送數(shù)據(jù) new Thread(() -> { try { for (int i = 0; i < 10; i++) { for (SseEmitter e : emitters) { e.send("data: Event " + i + "\n\n"); } Thread.sleep(1000); // 每秒發(fā)送一次 } } catch (Exception e) { emitters.forEach(SseEmitter::completeWithError); } }).start(); return emitter; } }
總結(jié)
- 返回
text/event-stream
:在 Spring Boot 控制器中使用SseEmitter
或直接通過(guò)@GetMapping
返回流式數(shù)據(jù)。 - 前端接收事件:使用瀏覽器的
EventSource
API 來(lái)接收事件流。 - 定時(shí)事件:可以使用
@Scheduled
來(lái)定期推送事件,或者通過(guò)后臺(tái)線程推送動(dòng)態(tài)數(shù)據(jù)。 - 多客戶端支持:可以管理多個(gè)
SseEmitter
實(shí)例,為每個(gè)客戶端推送事件。
這種方式非常適合實(shí)時(shí)數(shù)據(jù)推送,例如股票行情更新、社交媒體通知、實(shí)時(shí)消息等應(yīng)用場(chǎng)景。
到此這篇關(guān)于Springboot 實(shí)現(xiàn)Server-Sent Events的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)Springboot實(shí)現(xiàn)Server-Sent Events內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
將本地JAR文件手動(dòng)添加到Maven本地倉(cāng)庫(kù)的實(shí)現(xiàn)過(guò)程
在Java開(kāi)發(fā)中,使用Maven作為項(xiàng)目管理工具已經(jīng)成為了主流的選擇,Maven提供了強(qiáng)大的依賴管理功能,可以輕松地下載和管理項(xiàng)目所需的庫(kù)和工具,在某些情況下,你可能會(huì)需要將本地下載的JAR文件手動(dòng)添加到Maven的本地倉(cāng)庫(kù)中,這篇博客將詳細(xì)介紹如何實(shí)現(xiàn)這一過(guò)程2024-10-10Java實(shí)戰(zhàn)之實(shí)現(xiàn)一個(gè)好用的MybatisPlus代碼生成器
這篇文章主要介紹了Java實(shí)戰(zhàn)之實(shí)現(xiàn)一個(gè)好用的MybatisPlus代碼生成器,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Java常見(jiàn)問(wèn)題之javac Hello.java找不到文件的解決方法
剛開(kāi)始編寫(xiě)java代碼時(shí),肯定會(huì)遇到各種各樣的bug,當(dāng)然對(duì)于初學(xué)者這也是能理解的,下面這篇文章主要給大家介紹了關(guān)于Java常見(jiàn)問(wèn)題之javac Hello.java找不到文件解決的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下。2018-01-01java讀取文件:char的ASCII碼值=65279,顯示是一個(gè)空字符的解決
這篇文章主要介紹了java讀取文件:char的ASCII碼值=65279,顯示是一個(gè)空字符的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08JavaWeb Session 會(huì)話管理實(shí)例詳解
這篇文章主要介紹了JavaWeb Session 會(huì)話管理的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-09-09springboot-mongodb的多數(shù)據(jù)源配置的方法步驟
這篇文章主要介紹了springboot-mongodb的多數(shù)據(jù)源配置的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04使用Java編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的工具類(lèi)
這篇文章主要介紹了如何使用Java來(lái)編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的程序,包括一個(gè)針對(duì)各種數(shù)據(jù)庫(kù)通用的釋放資源的工具類(lèi)的寫(xiě)法,需要的朋友可以參考下2016-03-03