Spring Boot 2.7.8 原生 SSE 服務(wù)端開發(fā)實(shí)戰(zhàn)指南
前言
在當(dāng)今的互聯(lián)網(wǎng)應(yīng)用開發(fā)中,實(shí)時(shí)數(shù)據(jù)交互的需求日益增長。無論是股票交易系統(tǒng)中實(shí)時(shí)更新的股價(jià)信息,還是社交平臺(tái)上的即時(shí)消息推送,亦或是物聯(lián)網(wǎng)場景下傳感器數(shù)據(jù)的實(shí)時(shí)傳輸,都對(duì)后端服務(wù)提出了更高的要求。傳統(tǒng)的輪詢機(jī)制雖然簡單,但效率低下且資源消耗大;而WebSocket雖然功能強(qiáng)大,但在某些場景下顯得過于復(fù)雜且實(shí)現(xiàn)成本較高。在這種背景下,Server-Sent Events(SSE)作為一種輕量級(jí)的、基于HTTP協(xié)議的單向?qū)崟r(shí)通信技術(shù),逐漸受到開發(fā)者的關(guān)注。
SSE允許服務(wù)器主動(dòng)向客戶端推送數(shù)據(jù),而無需客戶端頻繁發(fā)起請(qǐng)求,這不僅提高了數(shù)據(jù)傳輸?shù)男?,還降低了服務(wù)器的負(fù)載。更重要的是,SSE的實(shí)現(xiàn)相對(duì)簡單,它基于標(biāo)準(zhǔn)的HTTP協(xié)議,無需額外的協(xié)議支持,這使得它在許多場景下成為理想的解決方案。Spring Boot作為目前最流行的Java微服務(wù)框架之一,提供了強(qiáng)大的功能和極高的開發(fā)效率。在Spring Boot 2.7.8版本中,我們可以利用其原生支持,輕松實(shí)現(xiàn)SSE服務(wù),從而為應(yīng)用提供實(shí)時(shí)數(shù)據(jù)推送能力。

本實(shí)戰(zhàn)教程將帶領(lǐng)讀者從零開始,逐步構(gòu)建一個(gè)基于Spring Boot 2.7.8的SSE服務(wù)端應(yīng)用。我們將從基礎(chǔ)的環(huán)境搭建開始,詳細(xì)介紹如何創(chuàng)建一個(gè)Spring Boot項(xiàng)目,并引入必要的依賴。接著,我們會(huì)深入探討SSE的核心概念,包括事件流的格式、數(shù)據(jù)推送的機(jī)制以及如何處理客戶端的連接和重連。通過具體的代碼示例,讀者將學(xué)會(huì)如何在Spring Boot中配置和使用SSE,實(shí)現(xiàn)從服務(wù)器到客戶端的實(shí)時(shí)數(shù)據(jù)推送。
此外,我們還將討論一些常見的問題和挑戰(zhàn),例如如何保證數(shù)據(jù)的實(shí)時(shí)性和準(zhǔn)確性、如何處理高并發(fā)場景下的性能問題,以及如何確保服務(wù)的穩(wěn)定性和可靠性。通過這些討論,讀者將能夠更好地應(yīng)對(duì)實(shí)際開發(fā)中可能遇到的各種情況,從而構(gòu)建出高效、穩(wěn)定且可擴(kuò)展的SSE服務(wù)。無論你是剛剛接觸Spring Boot的初學(xué)者,還是已經(jīng)有一定經(jīng)驗(yàn)的開發(fā)者,希望通過本教程的學(xué)習(xí),你能夠掌握SSE技術(shù)的核心要點(diǎn),并將其應(yīng)用到自己的項(xiàng)目中。讓我們一起開啟這場Spring Boot原生SSE服務(wù)端開發(fā)的實(shí)戰(zhàn)之旅,探索實(shí)時(shí)數(shù)據(jù)交互的奧秘,提升你的應(yīng)用性能和用戶體驗(yàn)。
一、SSE知識(shí)簡介
在正式開始介紹在SpringBoot中如何實(shí)現(xiàn)SSE服務(wù)時(shí),為了方便第一次學(xué)習(xí)的朋友對(duì)SSE的機(jī)制有一個(gè)基本的了解,這里我們首先對(duì)SSE進(jìn)行一個(gè)簡單的介紹。分別來簡單講講SSE是什么?SSE的工作原理是什么以及SSE適用于什么場景。
1、SSE是什么
SSE(Server-sent Events) 規(guī)范是 HTML 5 規(guī)范的一個(gè)組成部分,具體的規(guī)范文檔見參考資源。該規(guī)范比較簡單,主要由兩個(gè)部分組成:第一個(gè)部分是服務(wù)器端與瀏覽器端之間的通訊協(xié)議,第二部分則是在瀏覽器端可供 JavaScript 使用的 EventSource 對(duì)象。通訊協(xié)議是基于純文本的簡單協(xié)議。服務(wù)器端的響應(yīng)的內(nèi)容類型是“text/event-stream”。響應(yīng)文本的內(nèi)容可以看成是一個(gè)事件流,由不同的事件所組成。每個(gè)事件由類型和數(shù)據(jù)兩部分組成,同時(shí)每個(gè)事件可以有一個(gè)可選的標(biāo)識(shí)符。不同事件的內(nèi)容之間通過僅包含回車符和換行符的空行(“\r\n”)來分隔。每個(gè)事件的數(shù)據(jù)可能由多行組成。
2、SSE工作原理
客戶端發(fā)起請(qǐng)求:客戶端通過 EventSource API 向服務(wù)器發(fā)起一個(gè) HTTP GET 請(qǐng)求,請(qǐng)求頭中包含 Accept: text/event-stream,表明希望接收事件流。
服務(wù)器響應(yīng):服務(wù)器收到請(qǐng)求后,保持連接開放,并設(shè)置響應(yīng)頭 Content-Type: text/event-stream 和 Cache-Control: no-cache,以確保數(shù)據(jù)流不會(huì)被緩存。
數(shù)據(jù)推送:服務(wù)器通過保持開放的連接,以事件流的形式向客戶端發(fā)送數(shù)據(jù)。每個(gè)事件由字段組成,如 data(消息內(nèi)容)、event(事件類型)、id(消息編號(hào))和 retry(重連間隔)。
客戶端接收:客戶端通過監(jiān)聽事件流來獲取數(shù)據(jù),并在接收到事件后進(jìn)行處理。
自動(dòng)重連:如果連接中斷,客戶端會(huì)根據(jù) retry 字段的值自動(dòng)嘗試重新連接
3、SSE適用場景
說到SSE的使用場景,必不可少的就要提一下它的一個(gè)如影隨形的技術(shù)點(diǎn),WebSocket。眾所周知,WebSocket是一個(gè)全雙弓的通道,可以同時(shí)收發(fā)消息,同時(shí)WebSocket在面向Https的安全領(lǐng)域處理起來也是非常嚴(yán)格的。因此,在一些場景中,比如我們不需要進(jìn)行全雙工操作,只需要被動(dòng)的接受服務(wù)器端的信息推送即可??偨Y(jié)起來,SSE適用的場景如下:
實(shí)時(shí)通知:如新聞更新、消息提醒、股票價(jià)格變動(dòng)等,服務(wù)器可以實(shí)時(shí)向客戶端推送最新信息。
流式數(shù)據(jù):如日志流、傳感器數(shù)據(jù)等,客戶端可以持續(xù)接收服務(wù)器發(fā)送的數(shù)據(jù)流。
單向通信場景:當(dāng)只需要服務(wù)器向客戶端推送數(shù)據(jù),而客戶端無需向服務(wù)器發(fā)送數(shù)據(jù)時(shí),SSE 是一個(gè)簡單高效的選擇。
通過以上的介紹,相信大家對(duì)SSE的了解又加深了。介紹完這些基礎(chǔ)知識(shí)后,下面我們來重點(diǎn)介紹一下如何在SpringBoot中進(jìn)行SSE服務(wù)的實(shí)現(xiàn)。
二、SpringBoot中SSE的實(shí)現(xiàn)
Spring Boot作為目前最流行的Java微服務(wù)框架之一,提供了強(qiáng)大的功能和極高的開發(fā)效率。在Spring Boot 2.7.8版本中,我們可以利用其原生支持,輕松實(shí)現(xiàn)SSE服務(wù),從而為應(yīng)用提供實(shí)時(shí)數(shù)據(jù)推送能力。因此本節(jié)將重點(diǎn)介紹如何在SpringBoot中進(jìn)行SSE的實(shí)現(xiàn),分別從Maven依賴引入、SSE服務(wù)類實(shí)現(xiàn)、SSE控制器類和基于Thymeleaf的最簡單頁面實(shí)現(xiàn)等4個(gè)方面進(jìn)行介紹。
1、Maven中引入
這里直接給出我們的一個(gè)比較簡單的Pom依賴引入的示例,關(guān)鍵代碼如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.yelang</groupId> <artifactId>baidu-sse-client</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <!-- 兼容JDK 8的Spring Boot版本 --> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> <!-- 使用JDK 8 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <!-- Spring Boot WebFlux (包含WebClient) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- Spring Boot Web (可選,如果也需要傳統(tǒng)Web MVC) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Jackson JSON處理 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- SpringBoot集成thymeleaf模板 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 測(cè)試依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- 確保使用JDK 8編譯 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
2、SSE服務(wù)類實(shí)現(xiàn)
引入相關(guān)資源后,接下來就是非常重要的SSE服務(wù)類的實(shí)現(xiàn),這是整個(gè)SSE的核心。它不僅包含著連接的創(chuàng)建、銷毀,同時(shí)還包括了消息的發(fā)送,包括群發(fā)和單點(diǎn)發(fā)送。下面我們就分別來介紹這些功能實(shí)現(xiàn)。核心代碼如下:
package org.yelang.service;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class SseService {
// 保存所有連接的 emitter
private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
private final AtomicInteger counter = new AtomicInteger(0);
/**
* -創(chuàng)建新的 SSE 連接
*/
public SseEmitter createEmitter(String clientId) {
// 設(shè)置超時(shí)時(shí)間(0表示永不超時(shí))
SseEmitter emitter = new SseEmitter(0L);
emitters.put(clientId, emitter);
// 設(shè)置完成和超時(shí)回調(diào)
emitter.onCompletion(() -> {
emitters.remove(clientId);
System.out.println("SSE連接完成: " + clientId);
});
emitter.onTimeout(() -> {
emitters.remove(clientId);
System.out.println("SSE連接超時(shí): " + clientId);
});
emitter.onError((e) -> {
emitters.remove(clientId);
System.out.println("SSE連接錯(cuò)誤: " + clientId + ", 錯(cuò)誤: " + e.getMessage());
});
return emitter;
}
/**
* -發(fā)送消息給所有客戶端
*/
public void sendToAll(String message) {
emitters.forEach((clientId, emitter) -> {
try {
SseEmitter.SseEventBuilder event = SseEmitter.event().data(message)
.id(String.valueOf(counter.incrementAndGet())).name("message").reconnectTime(5000L);
emitter.send(event);
} catch (IOException e) {
emitter.completeWithError(e);
emitters.remove(clientId);
}
});
}
/**
* -發(fā)送消息給特定客戶端
*/
public void sendToClient(String clientId, String message) {
SseEmitter emitter = emitters.get(clientId);
if (emitter != null) {
try {
SseEmitter.SseEventBuilder event = SseEmitter.event().data(message)
.id(String.valueOf(counter.incrementAndGet())).name("message");
emitter.send(event);
} catch (IOException e) {
emitter.completeWithError(e);
emitters.remove(clientId);
}
}
}
/**
* -獲取當(dāng)前連接數(shù)
*/
public int getConnectionCount() {
return emitters.size();
}
}需要說明的是,這里為了演示方便,連接時(shí)間設(shè)置為永不超時(shí)。于此同時(shí),為了方便對(duì)連接進(jìn)行統(tǒng)一的管理,這里我們使用一個(gè)HashMap來進(jìn)行保存。對(duì)比群發(fā)和私發(fā)的消息的區(qū)別就是,群發(fā)是向所有客戶端統(tǒng)一進(jìn)行消息的推送,而私發(fā)就只有通信雙方才了解。
3、SSE控制器類實(shí)現(xiàn)
與常規(guī)的MVC應(yīng)用一樣,我們?cè)诤笈_(tái)也要實(shí)現(xiàn)一個(gè)SSE后臺(tái),這樣才能為前端頁面提供連接和發(fā)布消息。這里我們提供以下方法:
| 序號(hào) | 方法名 | 參數(shù)說明 |
| 1 | public String index(Model model) | 跳轉(zhuǎn)SSE管理首頁 |
| 2 | public SseEmitter streamSse(@RequestParam(value = "clientId", required = false) String clientId) | 建立 SSE 連接 |
| 3 | public String broadcastMessage(@RequestParam String message) | 廣播消息 |
| 4 | public String sendToClient(@RequestParam String clientId, @RequestParam String message) | 點(diǎn)對(duì)點(diǎn)發(fā)送消息 |
| 5 | public int getConnectionCount() | 獲取SSE連接數(shù) |
下面給出實(shí)例代碼:
package org.yelang.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.yelang.service.SseService;
import java.util.UUID;
@Controller
@RequestMapping("/sseman")
public class SseController {
@Autowired
private SseService sseService;
/**
* -首頁
*/
@GetMapping("/index")
public String index(Model model) {
model.addAttribute("connectionCount", sseService.getConnectionCount());
return "sse/index";
}
/**
* -建立 SSE 連接
*/
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamSse(@RequestParam(value = "clientId", required = false) String clientId) {
if (clientId == null || clientId.trim().isEmpty()) {
clientId = UUID.randomUUID().toString();
}
return sseService.createEmitter(clientId);
}
/**
* -發(fā)送消息給所有客戶端
*/
@PostMapping("/broadcast")
@ResponseBody
public String broadcastMessage(@RequestParam String message) {
sseService.sendToAll(message);
return "消息已廣播";
}
/**
* - 發(fā)送消息給特定客戶端
*/
@PostMapping("/send-to-client")
@ResponseBody
public String sendToClient(@RequestParam String clientId, @RequestParam String message) {
sseService.sendToClient(clientId, message);
return "消息已發(fā)送給客戶端: " + clientId;
}
/**
* -獲取連接數(shù)
*/
@GetMapping("/connection-count")
@ResponseBody
public int getConnectionCount() {
return sseService.getConnectionCount();
}
}4、最簡單頁面實(shí)現(xiàn)
下面我們以Thymeleaf為例,重點(diǎn)講解前端界面的SSE集成。大家可以根據(jù)實(shí)際的業(yè)務(wù)需要來修改。為了進(jìn)行頁面的展示,首先來定義頁面樣式,設(shè)置如下:
<style>
body {
font-family: Arial, sans-serif;
max-width: 90%;
margin: 0 auto;
padding: 5px;
}
.container {
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
.message-area {
height: 300px;
border: 1px solid #ccc;
padding: 10px;
overflow-y: auto;
background-color: #f9f9f9;
}
.input-group {
margin-bottom: 10px;
}
input, button {
padding: 8px;
margin: 5px;
}
button {
background-color: #007bff;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.status {
color: #28a745;
font-weight: bold;
}
.error {
color: #dc3545;
}
.message {
margin: 5px 0;
padding: 5px;
border-left: 3px solid #007bff;
background-color: white;
}
/* 新增樣式:雙列布局 */
.row-container {
display: flex;
gap: 20px;
}
.row-container .container {
flex: 1;
margin-bottom: 10px;
}
/* 響應(yīng)式設(shè)計(jì):小屏幕時(shí)恢復(fù)單列布局 */
@media (max-width: 768px) {
.row-container {
flex-direction: column;
}
}
</style>同時(shí),在頁面區(qū)域,我們分類連接區(qū)、發(fā)送區(qū)和消息展示區(qū),這里我們提供兩個(gè)面板進(jìn)行數(shù)據(jù)的搜集和發(fā)送相應(yīng)的事件。
<!-- 新增:將連接狀態(tài)和發(fā)送消息放在同一行 -->
<div class="row-container">
<div class="container">
<h4>連接狀態(tài)</h4>
<div>
<span>當(dāng)前連接數(shù): </span> <span id="connectionCount"
th:text="${connectionCount}" class="status">0</span>
</div>
<div>
<span>我的客戶端ID: </span> <span id="clientId" class="status">未連接</span>
</div>
<div class="input-group">
<button onclick="connectSSE()">連接 SSE</button>
<button onclick="disconnectSSE()" style="background-color: #dc3545;">斷開連接</button>
<button onclick="refreshConnectionCount()">刷新連接數(shù)</button>
</div>
</div>
<div class="container">
<h4>發(fā)送消息</h4>
<div class="input-group">
<input type="text" id="broadcastMessage" placeholder="輸入要廣播的消息">
<button onclick="broadcastMessage()">廣播給所有客戶端</button>
</div>
<div class="input-group">
<input type="text" id="targetClientId" placeholder="目標(biāo)客戶端ID">
<input type="text" id="privateMessage" placeholder="輸入私密消息">
<button onclick="sendPrivateMessage()">發(fā)送給特定客戶端</button>
</div>
</div>
</div>
<div class="container">
<h4>接收消息</h4>
<div id="messageArea" class="message-area">
<!-- 消息將在這里顯示 -->
</div>
</div>方便進(jìn)行頁面的標(biāo)記,這里我們創(chuàng)建一個(gè)生成clientid的方法,使用隨機(jī)數(shù)生成的方式,參考代碼如下:
function generateClientId() {
return 'client_' + Math.random().toString(36).substr(2, 9);
}在html中創(chuàng)建sse連接,并與后臺(tái)連接的代碼如下:
let eventSource = null;
let clientId = null;
var ctx = "/bdsse/sseman";
function connectSSE() {
if (eventSource) {
addMessage('警告', '已經(jīng)連接到SSE服務(wù)器');
return;
}
// 生成客戶端ID
clientId = generateClientId();
document.getElementById('clientId').textContent = clientId;
// 創(chuàng)建 EventSource 連接
eventSource = new EventSource(ctx + '/sse?clientId=' + clientId);
// 處理消息事件
eventSource.onmessage = function(event) {
addMessage('服務(wù)器消息', event.data);
};
// 處理自定義事件
eventSource.addEventListener('message', function(event) {
addMessage('自定義消息', event.data);
});
// 處理連接打開
eventSource.onopen = function(event) {
addMessage('系統(tǒng)', 'SSE連接已建立');
refreshConnectionCount();
};
// 處理錯(cuò)誤
eventSource.onerror = function(event) {
if (eventSource.readyState === EventSource.CLOSED) {
addMessage('系統(tǒng)', 'SSE連接已關(guān)閉');
} else {
addMessage('錯(cuò)誤', 'SSE連接錯(cuò)誤: ' + event);
}
};
addMessage('系統(tǒng)', '正在連接SSE服務(wù)器...');
}通過這樣就可以通過請(qǐng)求后臺(tái)接口連接上SSE服務(wù)端,如果想要斷開連接可以調(diào)用以下方法:
function disconnectSSE() {
console.log("斷開連接");
if (eventSource) {
eventSource.close();
eventSource = null;
addMessage('系統(tǒng)', 'SSE連接已斷開');
refreshConnectionCount();
} else {
addMessage('警告', '沒有活動(dòng)的SSE連接');
}
}更多具體的應(yīng)用和代碼將在下一節(jié)中進(jìn)行詳細(xì)講解。
三、成果展示
本節(jié)將結(jié)合具體的頁面和相關(guān)SSE的處理方法講解一個(gè)實(shí)際的消息發(fā)送與接收實(shí)例。
1、SSE連接
在控制臺(tái)中啟動(dòng)服務(wù)后,在瀏覽器中輸入訪問地址,即可打開如下界面:

可以看到在消息欄中已經(jīng)顯示連接SSE服務(wù)器成功。接下來就可以進(jìn)行消息廣播和點(diǎn)對(duì)點(diǎn)發(fā)送。
2、群發(fā)消息
群發(fā)消息很容易理解,就是通知所有連接的客戶端,同時(shí)在客戶端顯示發(fā)送的消息。群發(fā)消息的處理代碼如下:
function broadcastMessage() {
const message = document.getElementById('broadcastMessage').value;
if (!message) {
alert('請(qǐng)輸入消息');
return;
}
fetch(ctx + '/broadcast', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'message=' + encodeURIComponent(message)
})
.then(response => response.text())
.then(data => {
addMessage('操作', data);
document.getElementById('broadcastMessage').value = '';
})
.catch(error => {
addMessage('錯(cuò)誤', '發(fā)送失敗: ' + error);
});
}為了方便演示,我們打開兩個(gè)標(biāo)簽頁,在新打開的標(biāo)簽中也連接SSE服務(wù)器,界面如下:

在任意一個(gè)客戶端中輸入需要群發(fā)的消息,比如:hello world,大家好。然后點(diǎn)擊“廣播給所有客戶端”按鈕,再來看每個(gè)客戶端可以收到以下內(nèi)容:

3、點(diǎn)對(duì)點(diǎn)消息
使用SSE除了可以實(shí)現(xiàn)群發(fā)消息之外,也可以實(shí)現(xiàn)向某指定客戶端發(fā)送消息,即點(diǎn)對(duì)點(diǎn)私發(fā)消息,實(shí)現(xiàn)代碼如下:
function sendPrivateMessage() {
const targetClientId = document.getElementById('targetClientId').value;
const message = document.getElementById('privateMessage').value;
if (!targetClientId || !message) {
alert('請(qǐng)輸入客戶端ID和消息');
return;
}
fetch(ctx + '/send-to-client', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'clientId=' + encodeURIComponent(targetClientId) +
'&message=' + encodeURIComponent(message)
})
.then(response => response.text())
.then(data => {
addMessage('操作', data);
document.getElementById('privateMessage').value = '';
})
.catch(error => {
addMessage('錯(cuò)誤', '發(fā)送失敗: ' + error);
});
}將目標(biāo)客戶端的clientID記下來之后,就可以實(shí)現(xiàn)向這個(gè)客戶端進(jìn)行發(fā)送,然后點(diǎn)擊發(fā)送特定客戶端,在接收端和發(fā)送端可以看到以下消息:

來檢查一下其它第三方的客戶端,能否接收消息:

從圖上可以看到,目標(biāo)客戶端成功接收消息,而非目標(biāo)客戶端則沒有收到消息,即實(shí)現(xiàn)了點(diǎn)對(duì)點(diǎn)私發(fā)消息。
四、總結(jié)
以上就是文本的主要內(nèi)容,本實(shí)戰(zhàn)教程將帶領(lǐng)讀者從零開始,逐步構(gòu)建一個(gè)基于Spring Boot 2.7.8的SSE服務(wù)端應(yīng)用。我們將從基礎(chǔ)的環(huán)境搭建開始,詳細(xì)介紹如何創(chuàng)建一個(gè)Spring Boot項(xiàng)目,并引入必要的依賴。接著,我們會(huì)深入探討SSE的核心概念,包括事件流的格式、數(shù)據(jù)推送的機(jī)制以及如何處理客戶端的連接和重連。通過具體的代碼示例,讀者將學(xué)會(huì)如何在Spring Boot中配置和使用SSE,實(shí)現(xiàn)從服務(wù)器到客戶端的實(shí)時(shí)數(shù)據(jù)推送。行文倉促,定有不足之處,歡迎各位朋友在評(píng)論區(qū)批評(píng)指正,不勝感激。
到此這篇關(guān)于Spring Boot 2.7.8 原生 SSE 服務(wù)端開發(fā)實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Spring Boot SSE 服務(wù)端開發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Springboot使用SSE推送消息到客戶端的實(shí)現(xiàn)
- SpringBoot整合SSE接口實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送
- SpringBoot集成MCP實(shí)現(xiàn)SSE實(shí)時(shí)通信功能
- springboot整合阿里云百煉DeepSeek實(shí)現(xiàn)sse流式打印的操作方法
- SpringBoot?2.x?接入非標(biāo)準(zhǔn)SSE格式大模型流式響應(yīng)的實(shí)戰(zhàn)解決方案
- springboot+vue實(shí)現(xiàn)SSE服務(wù)器發(fā)送事件的示例
- 使用Assembly打包和部署SpringBoot工程方式
- SpringBoot3中Spring?WebFlux?SSE服務(wù)器發(fā)送事件的實(shí)現(xiàn)步驟
- SpringBoot實(shí)現(xiàn)Server-Sent Events(SSE)的使用完整指南
- springboot實(shí)現(xiàn)SSE(Server?Sent?Event)的示例代碼
相關(guān)文章
Java中使用正則表達(dá)式獲取網(wǎng)頁中所有圖片的路徑
這篇文章主要介紹了Java中使用正則表達(dá)式獲取網(wǎng)頁中所有圖片的路徑,本文直接給出實(shí)例代碼,需要的朋友可以參考下2015-06-06
gradle配置國內(nèi)鏡像的實(shí)現(xiàn)
這篇文章主要介紹了gradle配置國內(nèi)鏡像的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
mybatis配置對(duì)象包含對(duì)象以及List的方式
這篇文章主要介紹了mybatis配置對(duì)象包含對(duì)象以及List的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java中synchronized與Lock的詳細(xì)對(duì)比
Lock和synchronized都是Java中用于實(shí)現(xiàn)線程同步的機(jī)制,但它們有一些重要的區(qū)別,這篇文章主要介紹了Java中synchronized與Lock的詳細(xì)對(duì)比,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-07-07
SpringCloud通過Feign傳遞List類型參數(shù)方式
這篇文章主要介紹了SpringCloud通過Feign傳遞List類型參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐
這篇文章主要介紹了springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
java實(shí)現(xiàn)的統(tǒng)計(jì)字符算法示例
這篇文章主要介紹了java實(shí)現(xiàn)的統(tǒng)計(jì)字符算法,涉及java針對(duì)字符的遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10

