Spring Boot 2.2.6調用DeepSeek API并通過SSE將流式響應推送給前端的完整實現

1. 添加依賴 (pom.xml)

<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SSE 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- HTTP客戶端 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId></dependency>
</dependencies>

2. 配置類 (WebClientConfig.java)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;@Configuration
public class WebClientConfig {@Beanpublic WebClient webClient() {return WebClient.builder().baseUrl("https://api.deepseek.com/v1").defaultHeader("Authorization", "Bearer YOUR_API_KEY") // 替換為你的API密鑰.build();}
}

3. 請求/響應DTO

import lombok.Data;
import java.util.List;@Data
public class DeepSeekRequest {private String model = "deepseek-chat";private List<Message> messages;private boolean stream = true;@Datapublic static class Message {private String role;private String content;public Message(String role, String content) {this.role = role;this.content = content;}}
}@Data
public class DeepSeekResponse {private List<Choice> choices;@Datapublic static class Choice {private Delta delta;}@Datapublic static class Delta {private String content;}
}

4. SSE服務實現 (DeepSeekService.java)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.DirectProcessor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxProcessor;
import reactor.core.publisher.FluxSink;import java.util.Collections;@Service
public class DeepSeekService {private final WebClient webClient;public DeepSeekService(WebClient webClient) {this.webClient = webClient;}public Flux<String> streamCompletion(String userMessage) {// 使用 FluxProcessor 替代 SinksFluxProcessor<String, String> processor = DirectProcessor.<String>create().serialize();FluxSink<String> sink = processor.sink();DeepSeekRequest request = new DeepSeekRequest();request.setMessages(Collections.singletonList(new DeepSeekRequest.Message("user", userMessage)));webClient.post().uri("/chat/completions").contentType(MediaType.APPLICATION_JSON).bodyValue(request).accept(MediaType.TEXT_EVENT_STREAM).retrieve().bodyToFlux(String.class).subscribe(data -> {ObjectMapper objectMapper = new ObjectMapper();try {String jsonString = objectMapper.writeValueAsString(data);sink.next(jsonString);} catch (JsonProcessingException e) {sink.error(e);}},sink::error,sink::complete);return processor;}
}

5. SSE控制器 (SseController.java)

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("/sse")
public class SseController {private final DeepSeekService deepSeekService;public SseController(DeepSeekService deepSeekService) {this.deepSeekService = deepSeekService;}@GetMapping(path = "/deepseek", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter streamDeepSeekResponse(@RequestParam String message) {SseEmitter emitter = new SseEmitter(60 * 1000L); // 60秒超時Flux<String> responseStream = deepSeekService.streamCompletion(message);responseStream.subscribe(content -> {try {// 發送SSE事件emitter.send(SseEmitter.event().data(content).name("message"));} catch (Exception e) {emitter.completeWithError(e);}},emitter::completeWithError,emitter::complete);return emitter;}
}

6. 前端實現 (HTML + JavaScript)

<!DOCTYPE html>
<html>
<head><title>DeepSeek SSE Demo</title>
</head>
<body><input type="text" id="message" placeholder="輸入你的問題"><button onclick="startSSE()">開始對話</button><div id="output" style="white-space: pre-wrap; margin-top: 20px;"></div><script>let eventSource;function startSSE() {const message = document.getElementById('message').value;const outputDiv = document.getElementById('output');outputDiv.innerHTML = ''; // 清空之前的內容if (eventSource) eventSource.close();// 創建SSE連接eventSource = new EventSource(`/sse/deepseek?message=${encodeURIComponent(message)}`);eventSource.addEventListener("message", (event) => {// 實時追加內容outputDiv.innerHTML += event.data;});eventSource.addEventListener("error", (err) => {console.error("SSE error:", err);outputDiv.innerHTML += "\n\n[連接已關閉]";eventSource.close();});}</script>
</body>
</html>

關鍵點說明:

????????SSE流式傳輸

????????使用SseEmitter實現服務端推送

????????通過text/event-stream內容類型保持長連接

DeepSeek API集成

設置stream=true啟用流式響應

? ? ? ? ?處理data: [DONE]結束標記

? ? ? ? ?解析JSON響應中的content字段

????????響應式編程

????????使用WebClient處理HTTP流

????????使用Sinks進行背壓管理

????????Flux實現響應式流處理

????????前端實現

????????使用EventSource?API接收SSE

????????實時追加內容到DOM

????????處理連接錯誤和關閉

測試步驟:

1.啟動Spring Boot應用

2.訪問前端頁面(默認端口8080)

3.輸入問題并點擊按鈕

4.查看實時輸出的思考過程

注意事項:

1.替換YOUR_API_KEY為實際的DeepSeek API密鑰

2.生產環境建議:

3.添加JSON解析庫(如Jackson)處理響應

4.增加錯誤處理和重試機制

5.添加API速率限制

6.實現更健壯的SSE連接管理

此實現能讓前端實時接收并顯示DeepSeek API返回的流式響應,實現"思考過程"的逐字顯示效果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86649.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86649.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86649.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LM1117-ADJ 簡單介紹

LM1117-ADJ是一款可調輸出電壓的低壓差線性穩壓器&#xff08;LDO&#xff09;&#xff0c;具有以下關鍵特性和應用要點&#xff1a; 核心特性 可調輸出電壓 通過外部分壓電阻&#xff08;R1和R2&#xff09;調節輸出電壓&#xff0c;范圍為1.25V至13.8V。輸出電壓公式&#…

知名流體控制解決方案供應商“永盛科技”與商派ShopeX達成B2B商城項目合作

2025年6月&#xff0c;全球知名的工業流體控制解決方案服務商——永盛科技&#xff08;股票&#xff1a;874497&#xff09;&#xff0c;與商派ShopeX正式達成B2B商城項目合作。 此次合作將共同推動永盛科技B2B業務的數字化變革&#xff0c;提高B2B業務運營效率&#xff0c;同…

jvm簡單八股

1、jvm中內存分為那幾個區域&#xff0c;1.7和1.8 jvm 中主要有 程序計數器、虛擬機棧、本地方法棧、堆、方法區、直接內存。 線程私有的有&#xff1a;程序計數器、虛擬機棧、本地方法棧 線程共有的有&#xff1a;堆、方法區、直接內存 堆空間又可以分為&#xff1a;新時代、…

contOS7安裝docker命令及yum源更換為國內源

docker介紹 Docker是一個開源的容器化平臺,通過將應用程序及其依賴打包成輕量級、可移植的容器,確保開發、測試和部署環境的一致性。Docker的核心概念包括容器、鏡像、Dockerfile和鏡像倉庫。容器是輕量級的虛擬化技術,共享宿主機內核但保持獨立運行環境,啟動快且資源占用少…

SpringBoot集成Redis-6.x版本流程

SpringBoot集成Redis是我們常見的功能&#xff0c;今天我們分享一下&#xff1a; 前言&#xff1a; 1、pom包引用 <!-- Redis Starter (默認使用 Lettuce) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boo…

zookeeper Curator(3):Watch事件監聽

文章目錄 Curator API 常用操作 Watch事件監聽NodeCachePathChildrenCacheTreeCache 本章代碼已分享至Gitee: https://gitee.com/lengcz/curator01 Curator API 常用操作 Watch事件監聽 zookeeper 允許用戶在指定節點上注冊一些Watcher &#xff0c;并且在一些特定事件觸發的時…

多模態融合相機L3CAM

多模態融合相機L3CAM L3CAM是Beamagine公司推出的多模態傳感器融合技術&#xff0c;結合了激光雷達&#xff08;LiDAR&#xff09;和可見光攝像頭&#xff0c;旨在為自動駕駛、工業機器人和其他需要精確環境感知的應用場景提供高效、安全的解決方案。 L3CAM技術參數 L3CAM結合…

結構化思維

前言 洞悉分析方法論 系統解決管理問題 1 構建問題分析框架 1.1 摘要 &#xff08;1&#xff09;何謂問題分析和解決&#xff1f; &#xff08;2&#xff09;問題分析和解決的基本原則 1.2 什么是問題分析與決策&#xff1f; 1.3 問題解決者需要具備的四種能力 &#xf…

什么是數字簽名(ECDSA)?

數字簽名是區塊鏈、數字身份認證和安全通信的核心技術之一&#xff0c;ECDSA&#xff08;橢圓曲線數字簽名算法&#xff09;是目前最常見、最主流的數字簽名算法之一&#xff0c;尤其在區塊鏈系統&#xff08;如比特幣、以太坊、EOS&#xff09;中廣泛應用。 一、什么是數字簽名…

深入剖析AI大模型:Dify的介紹

今天介紹的內容&#xff0c;跟大模型開發還是息息相關的。俗話說&#xff1a;有人的地方就是江湖&#xff01;對于我們技術其實也一樣&#xff0c;一個新技術的出現&#xff0c;自然會衍生出相應的生態圈。今天的文字只是介紹&#xff0c;以后會有專門的實操篇&#xff0c;主要…

Open VSX Registry關鍵漏洞使攻擊者可完全控制Visual Studio Code擴展市場

網絡安全研究人員近日披露了 Open VSX Registry&#xff08;"open-vsx[.]org"&#xff09;中存在的一個關鍵漏洞。若被成功利用&#xff0c;攻擊者可能完全控制整個 Visual Studio Code 擴展市場&#xff0c;造成嚴重的供應鏈風險。 漏洞詳情與潛在影響 Koi Securi…

Python從入門到高手9.1節-Python中的字典類型

目錄 9.1.1 理解字典類型 9.1.2 字典的類型名 9.1.3 字典的定義 9.1.4 字典的主要性質 9.1.5 好好學習&#xff0c;天天向上 9.1.1 理解字典類型 在日常生活中&#xff0c;我們常常會接觸到“字典”這種數據類型&#xff0c;例如一本書籍的目錄結構&#xff0c;在目錄結構…

封禁UDP端口提高防御能力分析

封禁不必要的 UDP 端口 確實可以在一定程度上提高系統的防御力&#xff0c;但這并不是一個絕對的“好”或“壞”的問題&#xff0c;需要根據具體情況來判斷。以下是詳細分析&#xff1a; ? 封禁 UDP 端口能提高防御力的原因 (優點) 減少攻擊面&#xff1a; 服務暴露&#xff…

阿里云-arms監控

監控java應用 若是容器集群環境&#xff0c;則選擇容器服務環境 手動安裝方式&#xff0c;是手動把 agent的jar包放到 ecs服務器&#xff0c;然后運行個人的spring boot服務時&#xff0c;加上一些參數&#xff0c;將agent也啟動運行 手動集成-添加agent 監控的是ecs中的java應…

c語言 char *str = ““ 和 char *str = NULL 以及 char str[] = {} 區別

目錄 前言char *str "" 和 char *str NULL 區別char *str NULL 和 char str[] {} 區別char *str "" 和 char str[] {} 區別char *str "" 和 const char *str "" 區別 前言 C語言指針的使用非常常見且易出錯&#xff0c;這里對…

小程序入門: tab bar 實現多頁面快速切換效果

在小程序開發中&#xff0c;tab bar 是實現多頁面快速切換的關鍵組件&#xff0c;能極大提升用戶體驗。上一篇我們完成了基礎配置&#xff0c;今天深入探索&#xff0c;打造更豐富實用的 tab bar 效果。 實現目標 這次要在小程序底部創建包含 “首頁”“消息”“聯系我們” 三…

Python 數據分析:numpy,抽提,多維切片索引

目錄 1 示例代碼2 歡迎糾錯3 免費爬蟲------以下關于 Markdown 編輯器新的改變功能快捷鍵合理的創建標題&#xff0c;有助于目錄的生成如何改變文本的樣式插入鏈接與圖片如何插入一段漂亮的代碼片生成一個適合你的列表創建一個表格設定內容居中、居左、居右SmartyPants 創建一個…

【向上教育】結構化面試概述.pdf

目 錄 第一章 面試須知—面試形式 .......................................................................................................... 1 一、結構化面試 .................................................................................................…

STM32F407控制單個張大頭閉環步進電機講解與梯形加減速(HAL庫)

文章目錄 硬件連接CubeMX配置**使用TIM5定時器CH3,即PA2作為脈沖控制&#xff0c;PE5控制方向&#xff08;TIM5_CH4是為控制雙電機做準備的可以先不配置&#xff09;** 設置占空比為50%,以下為AI講解重要&#xff01;&#xff01;&#xff01;定時器更新中斷脈沖觸發原理詳解PW…

MongoDB入門學習(含JAVA客戶端)

0.序章 致命的面試問題&#xff1a;為什么使用MongoDB&#xff1f; 大型的分布式的文檔型數據庫&#xff0c;也是NoSQL數據庫&#xff08;例如 redis&#xff09; MongoDB適合數據量大而價值又低的這種數據&#xff08;播放進度、評論、彈幕&#xff0c;實時數據的CRUD&…