SpringBoot快速接入DeepSeek?api(帶頁面)保姆級(jí)教程
一.前往deepseek官網(wǎng)申請Api key



二.java端接入
首先展示項(xiàng)目結(jié)構(gòu)

1.pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chat</groupId>
<artifactId>chat_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>chat_demo</name>
<description>chat_demo</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<!-- 添加Thymeleaf依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.35</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- HTTP客戶端 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.chat.chat_demo.ChatDemoApplication</mainClass>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.springboot配置文件 application.yaml
ai:
config:
deepseek:
apiKey: 填寫官網(wǎng)申請的Key
baseUrl: https://api.deepseek.com/chat/completions
server:
port: 8080
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
3.編寫controller接口
package com.chat.chat_demo.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RestController
@RequestMapping("deepSeek")
@Slf4j
public class OpenAIController {
@Value("${ai.config.deepseek.apiKey}")
private String API_KEY;
@Value("${ai.config.deepseek.baseUrl}")
private String API_URL;
// 用于保存每個(gè)用戶的對話歷史
//https://api.deepseek.com/chat/completions 此接口為無狀態(tài)接口,需要上下文連貫對話需要將歷史聊天記錄一并發(fā)送至接口中
private final Map<String, List<Map<String, String>>> sessionHistory = new ConcurrentHashMap<>();
private final ExecutorService executorService = Executors.newCachedThreadPool();
private final ObjectMapper objectMapper = new ObjectMapper();
@GetMapping()
public ModelAndView chat(ModelAndView modelAndView) {
modelAndView.setViewName("chat");
return modelAndView;
}
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chat(
// @RequestHeader("Authorization") String token,
@RequestBody String question) {
// 假設(shè) token 是用戶的唯一標(biāo)識(shí)
// String userId = token; // 或者從 token 中解析出用戶 ID
String userId = "123"; // 或者從 token 中解析出用戶 ID
SseEmitter emitter = new SseEmitter(-1L);
executorService.execute(() -> {
try {
log.info("流式回答開始, 問題: {}", question);
// 獲取當(dāng)前用戶的對話歷史
List<Map<String, String>> messages = sessionHistory.getOrDefault(userId, new ArrayList<>());
// 添加用戶的新問題到對話歷史
Map<String, String> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", question);
Map<String, String> systemMessage = new HashMap<>();
systemMessage.put("role", "system");
systemMessage.put("content", "聚城網(wǎng)絡(luò)科技有限公司的物業(yè)管理助手");
messages.add(userMessage);
messages.add(systemMessage);
// 調(diào)用 Deepseek API
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpPost request = new HttpPost(API_URL);
request.setHeader("Content-Type", "application/json");
request.setHeader("Authorization", "Bearer " + API_KEY);
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("model", "deepseek-chat");
// requestMap.put("model", "deepseek-reasoner");
requestMap.put("messages", messages); // 包含對話歷史
requestMap.put("stream", true);
String requestBody = objectMapper.writeValueAsString(requestMap);
request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
try (CloseableHttpResponse response = client.execute(request);
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
StringBuilder aiResponse = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("data: ")) {
System.err.println(line);
String jsonData = line.substring(6);
if ("[DONE]".equals(jsonData)) {
break;
}
JsonNode node = objectMapper.readTree(jsonData);
String content = node.path("choices")
.path(0)
.path("delta")
.path("content")
.asText("");
if (!content.isEmpty()) {
emitter.send(content);
aiResponse.append(content); // 收集 AI 的回復(fù)
}
}
}
// 將 AI 的回復(fù)添加到對話歷史
Map<String, String> aiMessage = new HashMap<>();
aiMessage.put("role", "assistant");
aiMessage.put("content", aiResponse.toString());
messages.add(aiMessage);
// 更新會(huì)話狀態(tài)
sessionHistory.put(userId, messages);
log.info("流式回答結(jié)束, 問題: {}", question);
emitter.complete();
}
} catch (Exception e) {
log.error("處理 Deepseek 請求時(shí)發(fā)生錯(cuò)誤", e);
emitter.completeWithError(e);
}
} catch (Exception e) {
log.error("處理 Deepseek 請求時(shí)發(fā)生錯(cuò)誤", e);
emitter.completeWithError(e);
}
});
return emitter;
}
}
4.編寫前端界面 chat.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DeepSeek Chat</title>
<style>
:root {
--primary-color: #5b8cff;
--user-bg: linear-gradient(135deg, #5b8cff 0%, #3d6ef7 100%);
--bot-bg: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
min-height: 100vh;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.chat-container {
width: 100%;
max-width: 800px;
height: 90vh;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: var(--shadow);
backdrop-filter: blur(10px);
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
padding: 24px;
background: var(--primary-color);
color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.chat-header h1 {
margin: 0;
font-size: 1.8rem;
font-weight: 600;
letter-spacing: -0.5px;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 12px;
}
.chat-message {
max-width: 75%;
padding: 16px 20px;
border-radius: 20px;
line-height: 1.5;
animation: messageAppear 0.3s ease-out;
position: relative;
word-break: break-word;
}
.chat-message.user {
background: var(--user-bg);
color: white;
align-self: flex-end;
border-bottom-right-radius: 4px;
box-shadow: var(--shadow);
}
.chat-message.bot {
background: var(--bot-bg);
color: #2d3748;
align-self: flex-start;
border-bottom-left-radius: 4px;
box-shadow: var(--shadow);
}
.chat-input {
padding: 20px;
background: rgba(255, 255, 255, 0.9);
border-top: 1px solid rgba(0, 0, 0, 0.05);
display: flex;
gap: 12px;
}
.chat-input input {
flex: 1;
padding: 14px 20px;
border: 2px solid rgba(0, 0, 0, 0.1);
border-radius: 16px;
font-size: 1rem;
transition: all 0.2s ease;
background: rgba(255, 255, 255, 0.8);
}
.chat-input input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(91, 140, 255, 0.2);
}
.chat-input button {
padding: 12px 24px;
border: none;
border-radius: 16px;
background: var(--primary-color);
color: white;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
.chat-input button:hover {
background: #406cff;
transform: translateY(-1px);
}
.chat-input button:disabled {
background: #c2d1ff;
cursor: not-allowed;
transform: none;
}
.chat-input button svg {
width: 18px;
height: 18px;
fill: currentColor;
}
@keyframes messageAppear {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.typing-indicator {
display: inline-flex;
gap: 6px;
padding: 12px 20px;
background: var(--bot-bg);
border-radius: 20px;
align-self: flex-start;
}
.typing-dot {
width: 8px;
height: 8px;
background: rgba(0, 0, 0, 0.3);
border-radius: 50%;
animation: typing 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(2) {
animation-delay: 0.2s;
}
.typing-dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes typing {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
@media (max-width: 640px) {
body {
padding: 10px;
}
.chat-container {
height: 95vh;
border-radius: 16px;
}
.chat-message {
max-width: 85%;
}
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h1>聚城網(wǎng)絡(luò)科技有限公司 DeepSeek Chat</h1>
</div>
<div class="chat-messages" id="chatMessages"></div>
<div class="chat-input">
<input type="text" id="questionInput" placeholder="輸入消息..." onkeydown="handleKeyDown(event)">
<button id="sendButton" disabled>
<svg viewBox="0 0 24 24">
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
</svg>
發(fā)送
</button>
</div>
</div>
<script>
const questionInput = document.getElementById('questionInput');
const sendButton = document.getElementById('sendButton');
const chatMessages = document.getElementById('chatMessages');
let isBotResponding = false;
// 輸入驗(yàn)證
questionInput.addEventListener('input', () => {
sendButton.disabled = questionInput.value.trim().length === 0;
});
// 回車發(fā)送
function handleKeyDown(e) {
if (e.key === 'Enter' && !sendButton.disabled && !isBotResponding) {
sendButton.click();
}
}
// 修改后的消息處理邏輯
let currentBotMessage = null; // 當(dāng)前正在更新的AI消息
async function handleBotResponse(response) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
currentBotMessage = displayMessage('bot', '');
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
// 處理最后剩余的數(shù)據(jù)
if (buffer) processLine(buffer);
break;
}
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
// 保留未完成的行在緩沖區(qū)
buffer = lines.pop() || '';
lines.forEach(line => {
if (line.startsWith('data:')) {
const data = line.replace(/^data:\s*/g, '').trim();
if (data === '[DONE]') return;
currentBotMessage.textContent += data;
}
});
chatMessages.scrollTop = chatMessages.scrollHeight;
}
} finally {
currentBotMessage = null;
}
}
// 發(fā)送邏輯
sendButton.addEventListener('click', async () => {
if (isBotResponding) return;
const question = questionInput.value.trim();
if (!question) return;
questionInput.value = '';
sendButton.disabled = true;
isBotResponding = true;
// 顯示用戶消息(新消息始終出現(xiàn)在下方)
displayMessage('user', question);
try {
// 顯示加載狀態(tài)
const typingIndicator = createTypingIndicator();
const response = await fetch('/deepSeek/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'text/event-stream'
},
body: JSON.stringify({ question }),
});
typingIndicator.remove();
await handleBotResponse(response); // 處理流式響應(yīng)
} catch (error) {
displayMessage('bot', '暫時(shí)無法處理您的請求,請稍后再試');
} finally {
isBotResponding = false;
questionInput.focus();
}
});
// 創(chuàng)建消息元素
function displayMessage(sender, content) {
const messageDiv = document.createElement('div');
messageDiv.className = `chat-message ${sender}`;
messageDiv.textContent = content;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
return messageDiv;
}
// 創(chuàng)建輸入指示器
function createTypingIndicator() {
const container = document.createElement('div');
container.className = 'typing-indicator';
container.innerHTML = `
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
`;
chatMessages.appendChild(container);
chatMessages.scrollTop = chatMessages.scrollHeight;
return container;
}
// 更新 AI 消息
// let currentBotMessage = null;
// function updateBotMessage(content) {
// if (!currentBotMessage) {
// currentBotMessage = displayMessage('bot', content);
// } else {
// currentBotMessage.textContent = content;
// }
// chatMessages.scrollTop = chatMessages.scrollHeight;
// }
</script>
</body>
</html>
三.測試
- 啟動(dòng)項(xiàng)目,訪問 http://localhost:8080/deepSeek 即可出現(xiàn)頁面,開始對話即可

總結(jié)
到此這篇關(guān)于SpringBoot快速接入DeepSeek api(帶頁面)的文章就介紹到這了,更多相關(guān)SpringBoot快速接入DeepSeek api內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot兩種方式接入DeepSeek的實(shí)現(xiàn)
- SpringBoot調(diào)用DeepSeek接口的實(shí)現(xiàn)
- SpringBoot或SpringAI對接DeepSeek大模型的詳細(xì)步驟
- SpringBoot接入deepseek深度求索示例代碼(jdk1.8)
- SpringBoot整合DeepSeek實(shí)現(xiàn)AI對話功能
- SpringBoot調(diào)用DeepSeek?API的完整操作指南
- springboot接入deepseek深度求索代碼示例(java版)
- springboot集成Deepseek4j的項(xiàng)目實(shí)踐
相關(guān)文章
Java中的interrupt、interrupted和isInterrupted方法區(qū)別詳解
這篇文章主要介紹了Java中的interrupt、interrupted和isInterrupted方法區(qū)別詳解,interrupt用于中斷線程,調(diào)用該方法的線程的狀態(tài)將會(huì)被設(shè)置為中斷狀態(tài),線程中斷僅僅是設(shè)置線程的中斷狀態(tài)位,并不會(huì)停止線程,需要用戶自己去監(jiān)視線程的狀態(tài)并作出處理,需要的朋友可以參考下2023-12-12
JAVA中通過自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法
java 自定義注解驗(yàn)證可自己添加所需要的注解,下面這篇文章主要給大家介紹了關(guān)于JAVA中通過自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08
詳解Java程序啟動(dòng)時(shí)-D指定參數(shù)是什么
java服務(wù)啟動(dòng)的時(shí)候,都會(huì)指定一些參數(shù),下面這篇文章主要給大家介紹了關(guān)于Java程序啟動(dòng)時(shí)-D指定參數(shù)是什么的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別
這篇文章主要介紹了聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Mybatis-plus出現(xiàn)數(shù)據(jù)庫id很大或者為負(fù)數(shù)的解決
本文主要介紹了Mybatis-plus出現(xiàn)數(shù)據(jù)庫id很大或者為負(fù)數(shù)的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
java對象轉(zhuǎn)成byte數(shù)組的3種方法
這篇文章主要為大家詳細(xì)介紹了java對象轉(zhuǎn)成byte數(shù)組的3種方法,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2018-06-06
JAVA實(shí)現(xiàn)長連接(含心跳檢測Demo)
這篇文章主要介紹了JAVA實(shí)現(xiàn)長連接(含心跳檢測Demo),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10

