SpringBoot对接DeepSeek
文章目录
- Spring Boot 集成 DeepSeek API 详细步骤
- 1. 创建API Key
- 1.访问 [DeepSeek控制台](https://platform.deepseek.com/usage) 并登录。
- 2.点击 Create API Key 生成新密钥。
- 3.复制并保存密钥(需在Spring Boot配置文件中使用)。
- 2. 创建Spring Boot工程
- 3. 配置项目依赖
- 4. 核心代码实现
- 4.1 定义响应实体类
- 4.2 控制器实现(支持SSE流式响应)
- 5. 配置文件说明
- 6. 测试与验证
- 6.1启动应用后,通过浏览器或工具发送请求:
- 6.2预期输出(流式响应):
Spring Boot 集成 DeepSeek API 详细步骤
1. 创建API Key
1.访问 DeepSeek控制台 并登录。

2.点击 Create API Key 生成新密钥。
3.复制并保存密钥(需在Spring Boot配置文件中使用)。
2. 创建Spring Boot工程
使用 Spring Initializr 创建项目,选择以下依赖:
-
Spring Web
-
Lombok(简化实体类代码)
3. 配置项目依赖
在 pom.xml 中添加必要依赖:
<!-- OkHttp 实现HTTP请求 -->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.12.0</version>
</dependency><!-- FastJSON 用于JSON解析 -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.48</version>
</dependency><!-- SSE 事件流支持 -->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp-sse</artifactId><version>4.12.0</version>
</dependency>
4. 核心代码实现
4.1 定义响应实体类
@Data
public class AiResult {private Integer code;private String message;private String sid;private String id;private Long created;private List<AiResultChoices> choices;private AiResultUsage usage;
}@Data
public class AiResultChoices {private AiResultDelta delta;private Integer index;
}@Data
public class AiResultDelta {private String role;private String content;
}@Data
public class AiResultUsage {private Integer prompt_tokens;private Integer completion_tokens;private Integer total_tokens;
}@Data
public class ContentDto {private String content;
}
4.2 控制器实现(支持SSE流式响应)
/*** DeepSeek AI接口请求控制器* 功能:处理SSE(Server-Sent Events)流式请求,与DeepSeek API交互* 主要职责:* 1. 接收前端SSE请求* 2. 构造DeepSeek API请求* 3. 处理流式响应并转发给客户端* 4. 管理连接生命周期和异常处理*/
@RestController
public class SeekController {// 日志记录器private static final Logger log = LoggerFactory.getLogger(SeekController.class);// 流式结束标识符(符合OpenAI标准)private static final String DONE_FLAG = "[DONE]";// HTTP请求超时时间(单位:秒)private static final int TIMEOUT_SECONDS = 60;// DeepSeek API端点private static final String AI_URL = "https://api.deepseek.com/chat/completions";// JSON媒体类型常量private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json");// 从配置文件注入API密钥@Value("${api.key}")private String apiKey;// OkHttp客户端配置(线程安全)private final OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) // 连接超时.readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) // 读取超时.writeTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) // 写入超时.build();/*** SSE请求处理入口* @param message 用户输入消息* @param response HTTP响应对象* @throws IOException 当响应流出现问题时抛出*/@GetMapping("/stream")public void handleSse(@RequestParam String message, HttpServletResponse response) throws IOException {// 配置SSE响应头configureSSEResponse(response);PrintWriter pw = null;try {// 获取响应输出流pw = response.getWriter();// 创建同步锁(初始计数器为1)CountDownLatch latch = new CountDownLatch(1);// 执行SSE请求executeSSERequest(pw, buildRequest(message), latch);// 等待异步操作完成(最大等待TIMEOUT_SECONDS秒)if (!latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {log.warn("SSE请求超时");}} catch (InterruptedException e) {// 正确处理线程中断Thread.currentThread().interrupt();log.error("请求被中断", e);response.sendError(503, "服务不可用");} catch (Exception e) {log.error("SSE请求异常", e);response.sendError(500, "服务器内部错误");} finally {// 确保关闭输出流if (pw != null) {try {pw.close();} catch (Exception e) {log.warn("关闭PrintWriter异常", e);}}}}/*** 配置SSE响应头* @param response HTTP响应对象*/private void configureSSEResponse(HttpServletResponse response) {response.setContentType("text/event-stream"); // MIME类型response.setCharacterEncoding("UTF-8"); // 字符编码response.setHeader("Connection", "keep-alive"); // 保持长连接response.setHeader("Cache-Control", "no-cache"); // 禁用缓存}/*** 构建DeepSeek API请求* @param content 用户输入内容* @return 构造好的Request对象*/private Request buildRequest(String content) {// 构造请求参数Map<String, Object> params = new HashMap<>();params.put("model", "deepseek-chat"); // 使用的模型params.put("stream", true); // 启用流式传输// 构造消息列表(使用双括号初始化语法)params.put("messages", Collections.singletonList(new HashMap<String, String>() {{put("role", "user"); // 消息角色put("content", content); // 消息内容}}));// 构建OkHttp请求return new Request.Builder().url(AI_URL) // API地址.post(RequestBody.create(JSON.toJSONString(params), JSON_MEDIA_TYPE)) // JSON请求体.addHeader("Authorization", "Bearer " + apiKey) // 认证头.addHeader("Accept", "text/event-stream") // 接受SSE流.build();}/*** 执行SSE请求核心方法* @param pw 响应输出流* @param request 构造好的API请求* @param latch 线程同步锁*/private void executeSSERequest(PrintWriter pw, Request request, CountDownLatch latch) {// 创建事件源监听器RealEventSource eventSource = new RealEventSource(request, new EventSourceListener() {/*** 事件处理回调* @param eventSource 事件源* @param id 事件ID(未使用)* @param type 事件类型(未使用)* @param data 接收到的数据*/@Overridepublic void onEvent(EventSource eventSource, String id, String type, String data) {try {// 处理结束标志if (DONE_FLAG.equals(data)) {sendData(pw, new ContentDto(DONE_FLAG));return;}// 解析并发送有效内容String content = parseContent(data);if (!content.isEmpty()) {sendData(pw, new ContentDto(content));}} catch (Exception e) {log.error("事件处理异常", e);}}/*** 失败处理回调*/@Overridepublic void onFailure(EventSource eventSource, Throwable t, Response response) {log.error("API调用失败: {},响应码:{}", t.getMessage(), (response != null ? response.code() : "N/A"));latch.countDown(); // 释放同步锁}/*** 连接关闭回调*/@Overridepublic void onClosed(EventSource eventSource) {try {sendData(pw, new ContentDto(DONE_FLAG)); // 发送结束标志} finally {latch.countDown(); // 确保释放同步锁}}});// 发起异步连接eventSource.connect(httpClient);}/*** 线程安全的数据发送方法* @param pw 响应输出流* @param dto 要发送的数据传输对象*/private synchronized void sendData(PrintWriter pw, ContentDto dto) {try {// 按照SSE格式发送数据pw.write("data:" + JSON.toJSONString(dto) + "\n\n");pw.flush(); // 立即刷新缓冲区} catch (Exception e) {log.error("数据发送失败", e);}}/*** 解析API响应内容* @param data 原始响应字符串* @return 解析出的内容文本*/private String parseContent(String data) {try {// 使用FastJSON反序列化AiResult result = JSON.parseObject(data, AiResult.class);// 使用Optional处理可能为空的字段return Optional.ofNullable(result.getChoices()).flatMap(list -> list.stream().findFirst()) // 取第一个choice.map(AiResultChoices::getDelta) // 获取delta对象.map(AiResultDelta::getContent) // 获取content字段.orElse(""); // 默认返回空字符串} catch (Exception e) {log.error("数据解析异常,原始数据:{}", data, e);return "";}}
}
5. 配置文件说明
在 application.yml 中添加配置:
deepseek:api-key: your_api_key_here # 替换为实际API Key
6. 测试与验证
6.1启动应用后,通过浏览器或工具发送请求:
GET http://localhost:8080/stream?message=你好,介绍一下你自己
6.2预期输出(流式响应):

相关文章:
SpringBoot对接DeepSeek
文章目录 Spring Boot 集成 DeepSeek API 详细步骤1. 创建API Key1.访问 [DeepSeek控制台](https://platform.deepseek.com/usage) 并登录。2.点击 Create API Key 生成新密钥。3.复制并保存密钥(需在Spring Boot配置文件中使用)。 2. 创建Spring Boot工…...
doris:审计日志
Doris 提供了对于数据库操作的审计能力,可以记录用户对数据库的登陆、查询、修改操作。在 Doris 中,可以直接通过内置系统表查询审计日志,也可以直接查看 Doris 的审计日志文件。 开启审计日志 通过全局变量 enable_audit_plugin 可以随时…...
`fetch` 和 `axios`的前端使用区别
🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉 欢迎访问的个人博客&am…...
大语言模型的多垂类快速评估与 A/B 测试
简介 行业领先的模型构建企业携手澳鹏(Appen)开展了一项极具挑战性的项目。针对 3 至 6 个大型语言模型(LLM),在广泛的通用领域及复杂专业领域(如医疗保健、法律、金融、编程、数学和汽车行业等࿰…...
【RabbitMQ】RabbitMQ如何保证消息不丢失?
为了保证消息不丢失,需要在生产者、RabbitMQ本身和消费者三个环节采取相应措施。 1.生产者端:确保消息发送成功 1.1开启消息确认机制(Publisher Confirms) 原理: 生产者发送消息后,RabbitMQ会返回一个确认(ACK),表示消息已成功…...
RAGFlow + LlamaIndex 本地知识库RAG增强架构与实现直播智能复盘
一、需求分析与架构设计 基于 RAGFlow LlamaIndex 本地知识库RAG 扩展直播话术合规与复盘系统,需构建 实时流处理、多模态合规引擎、智能复盘分析 三层能力。以下是完整架构图与技术方案: 二、核心模块技术方案 1. 直播流实时处理(输入层→…...
《UNIX网络编程卷1:套接字联网API》第2章 传输层:TCP、UDP和SCTP
《UNIX网络编程卷1:套接字联网API》第2章 传输层:TCP、UDP和SCTP 2.1 传输层的核心作用与协议选型 传输层是网络协议栈中承上启下的核心层,直接决定应用的通信质量。其主要职责包括: 端到端通信:屏蔽底层网络细节&am…...
阿里云平台服务器操作以及发布静态项目
目录: 1、云服务器介绍2、云服务器界面3、发布静态项目1、启动nginx2、ngixn访问3、外网访问测试4、拷贝静态资源到nginx目录下并重启nginx 1、云服务器介绍 2、云服务器界面 实例详情:里面主要显示云服务的内外网地址以及一些启动/停止的操作。监控&…...
【大模型实战篇】使用GPTQ量化QwQ-32B微调后的推理模型
1. 量化背景 之所以做量化,就是希望在现有的硬件条件下,提升性能。量化能将模型权重从高精度(如FP32)转换为低精度(如INT8/FP16),内存占用可减少50%~75%。低精度运算(如INT8…...
Spring WebFlux之流式输出
🎉🎉🎉🎉🎉🎉 欢迎访问的个人博客:https://swzbk.site/,加好友,拉你入福利群 🎉🎉🎉🎉🎉🎉 流式输…...
基于springboot医疗平台系统(源码+lw+部署文档+讲解),源码可白嫖!
摘要 信息化时代,各行各业都以网络为基础飞速发展,而医疗服务行业的发展却进展缓慢,传统的医疗服务行业已经逐渐不满足民众的需求,有些还在以线下预约挂号的方式接待病人,为此设计一个医疗平台系统很有必要。此类系统…...
Stable Diffusion lora训练(一)
一、不同维度的LoRA训练步数建议 2D风格训练 数据规模:建议20-50张高质量图片(分辨率≥10241024),覆盖多角度、多表情的平面风格。步数范围:总步数控制在1000-2000步,公式为 总步数 Repeat Image Epoch …...
网络空间安全(37)获取webshell方法总结
一、直接上传获取Webshell 这是最常见且直接的方法,利用网站对上传文件的过滤不严或存在漏洞,直接上传Webshell文件。 常见场景: 许多PHP和JSP程序存在此类漏洞。例如,一些论坛系统允许用户上传头像或心情图标,攻击者可…...
第十三次CCF-CSP认证(含C++源码)
第十三次CCF-CSP认证 跳一跳满分题解 碰撞的小球满分题解遇到的问题 棋局评估满分题解 跳一跳 题目链接 满分题解 没什么好说的 基本思路就是如何用代码翻译题目所给的一些限制,以及变量应该如何更新,没像往常一样给一个n,怎么读入数据&…...
【Agent】OpenManus-Prompt组件详细分析
1. 提示词架构概述 OpenManus 的提示词组件采用了模块化设计,为不同类型的智能体提供专门的提示词模板。每个提示词模块通常包含两种核心提示词:系统提示词(System Prompt)和下一步提示词(Next Step Prompt࿰…...
swagger ui 界面清除登录信息的办法
我们在开发过程中,用swagger ui 测试接口的时候,可能会要修改当前登录的用户。 但是如果我们在谷歌中对调试的本地swagger ui 登录地址存储过账户密码,每次启动项目调试之后,都会自动登录swagger ui ,登录界面一闪就…...
TensorFlow 的基本概念和使用场景
TensorFlow 是一个由 Google 开发的开源机器学习框架,主要用于构建和训练深度学习模型。下面是一些 TensorFlow 的基本概念和使用场景: 基本概念: 张量(Tensor):在 TensorFlow 中,数据以张量的…...
基于x11vnc的ubuntu远程桌面
1、安装VNC服务 sudo apt install x11vnc -y2、创建连接密码 sudo x11vnc -storepasswd3、安装lightdm服务 x11vnc 在 默认的 GDM3 中不起作用,因此需要使用 lightdm 桌面管理环境 sudo apt install lightdm -y切换至lightdm,上一步已经切换则跳过该…...
Cursor解锁Claude Max,助力AI编程新突破!
Cursor 最新推出的 Claude Max 模型,以其卓越的性能和创新的能力,正在重新定义我们对 AI 辅助编程的认知。这款搭载 Claude3.7 大脑的超级模型,不仅具备超强智能,还凭借一系列技术突破,向传统 AI 编程工具发起了挑战。…...
created在vue3 script setup中的写法
在 Vue 2 里,created 是一个生命周期钩子函数,会在实例已经创建完成之后被调用,主要用于在实例初始化之后、数据观测和 event/watcher 事件配置之前执行代码。而在 Vue 3 的 <script setup> 语法糖里,不再有像 Vue 2 那样直…...
GenICam标准
GenICam的目标是为所有类型的相机提供一个统一的编程接口。无论相机使用的是哪种传输协议或实现了哪些功能,编程接口(API)都是一样的。 GenICam(Generic Interface for Cameras)是一个为工业相机和图像采集设备设计的…...
ESP8266 与 ARM7 接口-LPC2148 创建 Web 服务器以控制 LED
ESP8266 与 ARM7 接口-LPC2148 创建 Web 服务器以控制 LED ESP8266 Wi-Fi 收发器提供了一种将微控制器连接到网络的方法。它被广泛用于物联网项目,因为它便宜、体积小且易于使用。 在本教程中,我们将 ESP8266 Wi-Fi 模块与 ARM7-LPC2148 微控制器连接,并创建一个 Web 服务…...
智享三代 AI 无人直播系统:颠覆传统,重塑直播新格局
在当今数字化浪潮席卷全球的时代,直播行业作为互联网经济的重要组成部分,正以前所未有的速度蓬勃发展。从最初的娱乐直播兴起,到如今电商直播、知识付费直播等多元业态百花齐放,直播已然成为人们生活和商业活动中不可或缺的一环。…...
通过C#脚本更改材质球的参数
// 设置贴图Texture mTexture Resources.Load("myTexture", typeof(Texture )) as Texture;material.SetTexture("_MainTex", mTexture );// 设置整数material.SetInt("_Int", 1);// 设置浮点material.SetFloat("_Float", 0.1f);// 设…...
FPGA管脚约束
目录 前言 一、IO约束 二、延迟约束 前言 IO约束包括管脚约束和延迟约束。 一、IO约束 对管脚进行约束,对应的约束语句: set_property -dict {PACKAGE_PIN AJ16 IOSTANDARD LVCMOS18} [get_ports "led[0]" ] 上面是单端的管脚&…...
已在此计算机上安装相同或更高版本的 .NET Framework 4”安装报错问题
安裝低版本的 .netFramework會被拒絕 需要做兩件事 1,允許windows安裝低版本的.net framework “已在此计算机上安装相同或更高版本的 .NET Framework 4”安装报错问题-CSDN博客 2,設置完成後重新安裝低版本的 .net framework,要用對應開發版本的 Win10 电脑安…...
如何判断 MSF 的 Payload 是 Staged 还是 Stageless(含 Meterpreter 与普通 Shell 对比)
在渗透测试领域,Metasploit Framework(MSF)的 msfvenom 工具是生成 Payload(载荷)的核心利器。然而,当我们选择 Payload 时,经常会遇到一个问题:这个 Payload 是 Staged(…...
【万字总结】前端全方位性能优化指南(一)——Brotli压缩、CDN智能分发、资源合并
前言 2025年前端技术前沿呈现三大核心趋势:AI深度赋能开发全流程,智能工具如GitHub Copilot X和Cursor实现代码生成、实时协作与自动化审查,开发效率提升3倍以上;性能与架构革新,WebAssembly 2.0支持多线程与Rust内存优化,边缘计算将渲染延迟压至50ms内,微前端Module …...
二.使用ffmpeg对原始音频数据重采样并进行AAC编码
重采样:将音频三元组【采样率 采样格式 通道数】之中的任何一个或者多个值改变。 一.为什么要进行重采样? 1.原始音频数据和编码器的数据格式不一致 2.播放器要求的和获取的数据不一致 3.方便运算 二.本次编码流程 1.了解自己本机麦克风参数&#x…...
实现前端.ttf字体包的压缩
前言 平常字体包都有1M的大小,所以网络请求耗时会比较长,所以对字体包的压缩也是前端优化的一个点。但是前端如果想要特点字符打包成字体包,网上查阅资料后,都是把前端代码里面的字符获取,但是对于动态的内容…...
