spring boot# 手把手教你从零搭建 AI 对话系统 - React + Spring Boot 实战(二)
> 一个完整的类 ChatGPT 对话系统,支持流式输出、打断,会话历史,前后端分离架构,非常适合拿来练手熟悉技术实现或者面试使用,接上一篇前端 基于 Spring Boot 2.7.18 + MyBatis-Plus + JWT 的 AI 对话系统后端服务。 ## 技术栈 - **Spring Boot 2.7.18** - 核心框架 - **MyBatis-Plus 3.5.5** - ORM 框架 - **JWT** - 身份认证 - **MySQL 8.0** - 数据存储 - **DeepSeek API** - AI 对话能力 - **Knife4j** - API 文档 ## 核心功能 ### 1. 用户认证体系 采用 JWT Token 实现无状态认证: ```java // JwtUtil.java - Token 生成与验证 @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String generateToken(Long userId, String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + expiration); return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("username", username) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } } ``` ### 2. 用户级 API Key 管理 每个用户独立绑定自己的 DeepSeek API Key,存储于 `user.api_key` 字段: ```java // UserServiceImpl.java - 注册时保存用户 API Key @Override @Transactional public void register(RegisterRequest request) { User user = new User(); user.setUsername(request.getUsername()); user.setPassword(passwordEncoder.encode(request.getPassword())); user.setApiKey(request.getApiKey()); // 用户专属 API Key user.setStatus(1); save(user); } ``` ### 3. 流式对话实现 通过 SSE (Server-Sent Events) 实现流式响应: ```java // AiChatServiceImpl.java - 流式对话核心逻辑 @Override public void streamChat(ChatRequest request, Long userId, HttpServletResponse response) { // 1. 从用户获取 API Key User user = userService.getById(userId); String apiKey = user.getApiKey(); // 2. 设置 SSE 响应头 response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); // 3. 调用 DeepSeek API HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setRequestProperty("Authorization", "Bearer " + apiKey); // 4. 流式转发响应 try (BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { writer.write(line + "\n"); writer.flush(); // 解析内容保存到数据库 if (line.startsWith("data: ") && !line.equals("data: [DONE]")) { parseAndSaveContent(line, aiMessage); } } } } ``` ### 4. 会话与消息管理 - **会话表** (`chat_session`): 存储对话元数据 - **消息表** (`chat_message`): 存储对话内容,支持 `reasoning_content` 深度思考 ### 5. 打断功能实现 前端通过 `AbortController` 中断请求,后端检测连接状态: ```java // 检测客户端是否断开连接 private boolean isClientConnected(HttpServletResponse response, PrintWriter writer) { try { writer.write(""); writer.flush(); return !writer.checkError(); } catch (Exception e) { return false; } } ``` ## 项目结构 ``` src/main/java/com/webseek/ ├── common/ # 通用工具类 │ ├── JwtUtil.java │ ├── CurrentUser.java │ └── Result.java ├── config/ # 配置类 │ ├── WebConfig.java │ └── JwtInterceptor.java ├── controller/ # 控制器层 │ ├── AuthController.java │ ├── ChatController.java │ ├── SessionController.java │ └── UserController.java ├── service/ # 服务层 │ ├── AiChatService.java │ ├── UserService.java │ └── impl/ ├── entity/ # 实体类 │ ├── User.java │ ├── ChatSession.java │ └── ChatMessage.java ├── dto/ # 数据传输对象 │ ├── request/ │ └── response/ └── mapper/ # MyBatis Mapper ``` ## 数据库表结构 ```sql -- 用户表 CREATE TABLE `user` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL UNIQUE, `password` VARCHAR(100) NOT NULL, `nickname` VARCHAR(50), `api_key` VARCHAR(500), -- DeepSeek API Key `status` TINYINT DEFAULT 1, `deleted` TINYINT DEFAULT 0, `create_time` DATETIME, `update_time` DATETIME ); -- 会话表 CREATE TABLE `chat_session` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `session_id` VARCHAR(64) NOT NULL UNIQUE, `user_id` BIGINT NOT NULL, `title` VARCHAR(200) DEFAULT '新对话', `model` VARCHAR(50), `deleted` TINYINT DEFAULT 0, `create_time` DATETIME, `update_time` DATETIME ); -- 消息表 CREATE TABLE `chat_message` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `message_id` VARCHAR(64) NOT NULL UNIQUE, `session_id` VARCHAR(64) NOT NULL, `user_id` BIGINT NOT NULL, `role` VARCHAR(20) NOT NULL, -- user/assistant `content` TEXT, `reasoning_content` TEXT, -- 深度思考内容 `deleted` TINYINT DEFAULT 0, `create_time` DATETIME ); ``` ## 配置说明 修改 `application.yml` 中的数据库配置: ```yaml spring: datasource: url: jdbc:mysql://your-host:3306/webseek?useUnicode=true&characterEncoding=utf-8 username: your-username password: your-password ``` ## 启动方式 ```bash # 开发环境 mvn spring-boot:run # 打包 mvn clean package # 运行 java -jar target/webseek-backend-1.0.0.jar ``` ## API 文档 启动后访问:http://localhost:8090/doc.html ## 核心设计亮点 1. **用户级 API Key**: 每个用户独立配置,安全隔离 2. **流式响应**: SSE 实现打字机效果,支持实时打断 3. **JWT 认证**: 无状态设计,支持水平扩展 4. **逻辑删除**: MyBatis-Plus 自动处理软删除 5. **深度思考**: 支持 DeepSeek-R1 推理模型 源码地址[https://gitee.com/SongTaoo/react-webseek]






