项目概述与设计思路
在现代Web应用中,集成AI对话能力可以显著提升用户体验。本项目采用分层架构设计,将WebSocket实时通信与DeepSeek AI服务解耦,实现了可维护、可扩展的智能对话系统。
核心设计理念
- 接口隔离原则:通过接口定义服务契约,便于后续实现替换
- 单一职责原则:每个类只负责特定功能模块
- 实时通信:利用WebSocket实现低延迟的双向数据交换
详细代码解析
1. 服务层接口设计 - 定义AI服务契约
java
package com.qcby.websocket.service;
import java.io.IOException;
public interface DeepSeekService {
// 核心方法:向DeepSeek API发送问题并获取响应
String getDeepSeekResult(String question) throws IOException;
}
设计意图:
- 定义标准的AI服务接口,为后续可能的服务替换(如切换为其他AI提供商)提供便利
throws IOException明确声明可能出现的网络异常,强制调用方处理
2. 服务层实现 - DeepSeek API集成
java
package com.qcby.websocket.service.Impl;
import com.qcby.websocket.service.DeepSeekService;
import okhttp3.*;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service // Spring注解,将该类声明为服务层组件
public class DeepSeekServiceImpl implements DeepSeekService {
@Override
public String getDeepSeekResult(String question) throws IOException {
// 1. 创建HTTP客户端实例
OkHttpClient client = new OkHttpClient().newBuilder().build();
// 2. 设置请求内容类型为JSON
MediaType mediaType = MediaType.parse("application/json");
// 3. 构造符合DeepSeek API要求的请求体
String jsonBody = String.format("{\n"
+ " \"model\": \"deepseek-chat\",\n" // 指定使用的模型
+ " \"messages\": [\n" // 对话消息数组
+ " {\"role\": \"user\", \"content\": \"%s\"}\n" // 用户消息
+ " ],\n"
+ " \"temperature\": 0.7,\n" // 控制回复随机性(0-1)
+ " \"top_p\": 0.8\n" // 核采样参数,控制词汇选择范围
+ "}", question);
// 4. 创建请求体对象
RequestBody body = RequestBody.create(mediaType, jsonBody);
// 5. 构建完整的HTTP请求
Request request = new Request.Builder()
.url("https://api.deepseek.com/chat/completions") // API端点
.method("POST", body) // POST请求
.addHeader("Content-Type", "application/json") // 请求头
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer yourToken") // 认证令牌
.build();
// 6. 执行请求并获取响应
Response response = client.newCall(request).execute();
// 7. 返回响应体内容
return response.body().string();
}
}
关键技术点详解:
请求参数说明:
temperature:值越大回复越随机有创意,值越小回复越确定保守top_p:累计概率阈值,影响词汇选择的多样性
HTTP客户端选择:
- 使用OkHttp而非Spring的RestTemplate,因为OkHttp在处理大量并发请求时性能更优
- OkHttp支持连接池复用,减少TCP握手开销
3. WebSocket消息处理器 - 实时通信核心
java
@Component // Spring组件注解,纳入IoC容器管理
public class ChatHandler implements WebSocketHandler {
@Autowired // 依赖注入,Spring自动装配DeepSeekService实例
private DeepSeekService deepSeekService;
/**
* 用户会话管理Map
* Key: session.getId() - 会话唯一标识
* Value: WebSocketSession - 活跃的WebSocket会话对象
* static修饰确保所有ChatHandler实例共享同一会话集合
*/
public static final Map<String,WebSocketSession> USERSOCKETSESSION = new HashMap<>();
/**
* 连接建立成功回调
* 当客户端成功建立WebSocket连接时触发
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("新用户连接,会话ID:" + session.getId());
// 将新会话存入管理Map,便于后续消息定向发送
USERSOCKETSESSION.put(session.getId(), session);
}
/**
* 核心消息处理方法
* 当客户端发送消息到服务端时触发
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println("接收到来自会话[" + session.getId() + "]的消息:" + message.getPayload().toString());
// 步骤1:JSON反序列化 - 将客户端消息转换为Message对象
Message meg = GsonUtils.fromJson(message.getPayload().toString(), Message.class);
String question = meg.getMessage();
// 步骤2:调用AI服务 - 将用户问题发送给DeepSeek
String answer = deepSeekService.getDeepSeekResult(question);
// 步骤3:解析DeepSeek API响应
JSONObject jsonObject = new JSONObject(answer); // 将JSON字符串转换为对象
JSONArray choices = jsonObject.getJSONArray("choices"); // 获取choices数组
JSONObject choicesAnswer = choices.getJSONObject(0); // 获取第一个选择
JSONObject messageAnswer = choicesAnswer.getJSONObject("message"); // 获取消息内容
String content = messageAnswer.getString("content"); // 提取最终回复文本
System.out.println("AI回复内容:" + content);
// 步骤4:检查会话状态并返回响应
if(session.isOpen()){ // 重要:发送前检查连接是否仍然有效
// 构造TextMessage对象并发送给客户端
session.sendMessage(new TextMessage(content));
}
}
/**
* 群发消息功能 - 向所有在线用户广播消息
* 适用于公告、系统通知等场景
*/
public void sendMessageToAll(Message message) throws IOException {
// 遍历所有活跃会话
for (Map.Entry<String, WebSocketSession> entry : USERSOCKETSESSION.entrySet()){
final WebSocketSession webSocketSession = entry.getValue();
// 检查会话有效性后再发送
if(webSocketSession.isOpen()){
// 将Message对象序列化为JSON字符串
webSocketSession.sendMessage(new TextMessage(GsonUtils.toJson(message)));
}
}
}
/**
* 私聊功能 - 向指定用户发送消息
* @param userId 目标用户的会话ID
*/
public void sendMessageToUser(String userId, Message message) throws IOException {
// 根据用户ID从会话Map中查找对应会话
WebSocketSession webSocketSession = USERSOCKETSESSION.get(userId);
if(webSocketSession != null && webSocketSession.isOpen()){
webSocketSession.sendMessage(new TextMessage(GsonUtils.toJson(message)));
}
}
/**
* 传输错误处理 - 网络异常、协议错误等
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("会话[" + session.getId() + "]连接出错:" + exception.getMessage());
// 从会话管理中移除异常会话
USERSOCKETSESSION.remove(session.getId());
// 确保关闭异常会话,释放资源
if (session.isOpen()) {
session.close();
}
}
/**
* 连接关闭回调 - 客户端主动断开或超时断开
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.out.println("会话[" + session.getId() + "]已关闭,状态:" + closeStatus.toString());
// 清理会话资源
USERSOCKETSESSION.remove(session.getId());
}
/**
* 是否支持部分消息 - 对于大文件分片传输
*/
@Override
public boolean supportsPartialMessages() {
return false; // 本项目不处理大消息分片
}
}
核心架构优势
1. 会话管理机制
- 实时状态维护:通过HashMap实时跟踪所有在线用户
- 自动清理:连接异常或关闭时自动清理会话资源,防止内存泄漏
- 会话查找优化:O(1)时间复杂度的用户会话查找
2. 消息处理流程
客户端消息 → WebSocket接收 → JSON反序列化 → AI服务调用 → 响应解析 → WebSocket返回
3. 异常处理策略
- 网络异常:IOException处理API调用失败
- 会话异常:自动移除无效会话,保持系统稳定
- JSON解析异常:通过try-catch确保格式错误的响应不会导致系统崩溃