一次针对 EduMind 实时课堂模块的集中攻关,横跨安全、性能、可靠性和 AI 生成能力四个维度,一天内完成 16 项修复与功能新增。

一、安全纵向加固:学生身份防冒用

问题

/api/live/join 是公开接口,学生自报学号就能拿到合法 JWT。WebSocket Handler 又直接信任消息体中的 studentId,导致学生 A 可以任意冒用学生 B 的身份答题、举手、提问。

方案:四层纵深防御

  1. Join 入口验证 — 在 LiveSessionService.joinSession 中增加班级花名册校验:如果教师已导入学生名单,则不在名单内的学号拒绝加入
  2. WebSocket Handler 覆盖身份InteractionHandlerReactionHandlerQASessionHandler 全部改为从 STOMP Session Attributes(CONNECT 阶段 JWT 验证后存储)读取学生身份,忽略 payload 中的 studentId/studentName
  3. REST 端点修复markConfusion 从 JWT 提取身份而非请求体
  4. WebSocket CORS 收紧setAllowedOriginPatterns("*") 改为读取 app.cors.allowed-origins 配置

二、可靠性与性能

scheduleAutoClose 线程池化

InteractionService 中每次限时互动都 new Thread() sleep,改为共享 ScheduledExecutorService,支持手动关闭时取消定时任务,@PreDestroy 优雅退出。

倒计时同步

学生端倒计时从 setInterval(remaining--) 纯前端自减改为 deadlineEpochMs - Date.now() 实时计算。InteractionPushDTO 新增绝对截止时间戳字段,消除网络延迟和页面刷新带来的偏移。

教师断线检测

WebSocketAuthInterceptor 新增教师连接追踪,断开时通过 /topic/session/{sid}/teacher-status 广播 {online: false}。学生端收到后显示 “⚠️ 老师暂时离开” 红色提示。修复了 streamChat 不传 sessionId 的已有 Bug。

学生断线 30s 宽限期

StudentPresenceService 新增宽限期机制:学生 WebSocket 断开后启动 30s 定时器,超时才标记离场。宽限期内重连自动取消定时器,消除切 Wi-Fi 时的在线列表闪烁。

N+1 查询 → 批量查询

getInteractionHistorygetStudentProfile 中每次循环调 responseMapper.findByInteractionId() → 改为 findBySessionId 一次批量拉取 + 内存分组。20 个互动的课堂从 21 次查询降到 2 次。同步修复了 LiveNotificationService.sendPersonalizedReview 中的同类问题。

Presence 内存泄漏

LiveSessionService.endSession 新增调用 presenceService.clearSession(sessionId),结课时清理 onlineStudents map + 取消待执行的宽限期任务。

出勤持久化

新增 live_attendance_log 表(V8 迁移),studentJoined 写 JOIN 事件,studentLeft 写 LEAVE 事件。getClassId 使用 ConcurrentHashMap 缓存避免重复查 DB。

三、举手队列

新增 HandRaiseService + HandRaiseHandler,实现 FIFO 举手队列:

  • 学生举手入队,再点取消
  • 教师按序点名(队首出队)或指定点名
  • 教师可移除任意排队学生
  • 结课时自动清空队列
  • 教师端左侧栏新增队列面板,学生端 ✋ 改为 toggle 蓝色按钮

四、PPT → AI 生成教学材料

核心实现

新增 TeachingMaterialGenerator 服务,调用 OpenClaw → LLM 分析 PPT 内容,同时生成预习作业和课堂试题。

  • 预习作业 — prompt 模板 ppt-preview-generation.txt,输出 JSON + ===GUIDE=== 分隔符 + Markdown 导读
  • 课堂试题 — prompt 模板 ppt-quiz-generation.txt,输出混合题型 JSON 数组(CHOICE/OPEN/EXERCISE)

关键踩坑

  1. DeepSeek 超时 — 不是超时,是梯子 DNS 劫持导致 api.deepseek.com 解析出内网 IP,OpenClaw 安全层直接拦截 Blocked: resolves to private/internal/special-use IP address
  2. 流式返回空streamChat(message, sessionId, status) 的请求体 bug:buildRequestBody(message, null, agent, true)sessionId 参数根本没传进去,导致 Agent 行为异常
  3. JSON 解析失败 — 预习作业的 guideText 是长段 Markdown,换行引号导致 JSON 断裂。改为 ===GUIDE=== 分隔符方案,JSON 和 Markdown 分家
  4. session_id NOT NULL — 草稿题没有课堂 session,V9 迁移删除外键 + NOT NULL 约束;V11 迁移补充 class_idsource_doc_id
  5. INSERT 缺列source_doc_id 加到了列定义但漏了 VALUES 子句
  6. correct_key VARCHAR(10) 太短 — 简答题答案超长,V10 迁移扩为 TEXT

前端

知识库页面选中 PPT 文件后:

  • 文件详情面板显示”🤖 AI 生成教学材料”按钮
  • 弹窗内选班级 → 生成 → 审核编辑 → 逐条发布/保存
  • 下方展示该文档历史上生成的草稿列表,可点击查看详情或删除
  • Axios 请求超时从默认 10s 扩展到 120s

数据库迁移汇总

V8 出勤日志 → V9 草稿允许空 session_id → V10 扩 correct_key 字段 → V11 加 class_id → V12 加 source_doc_id

五、修改文件清单(共计 28 个文件)

类别 文件 改动
安全 LiveSessionService.java join 花名册验证
安全 InteractionHandler.java 从 Session 读身份
安全 ReactionHandler.java 同上
安全 QASessionHandler.java 同上,修复匿名
安全 LiveSessionController.java confusion 从 JWT 读身份
安全 WebSocketConfig.java CORS 收紧
安全 WebSocketAuthInterceptor.java 权限 + 教师追踪 + @Lazy
安全 JwtUtil.java 新增 getSubjectFromToken
安全 ClassStudentMapper.java 新增 existsByClassIdAndStudentId
可靠性 InteractionService.java scheduleAutoClose 线程池 + 倒计时 deadlineEpochMs
可靠性 StudentPresenceService.java 30s 宽限期 + clearSession + 出勤日志
可靠性 LiveSessionService.java endSession 清理 presence + 举手队列
可靠性 InteractionResponseMapper.java 新增 findBySessionId/sessionIds
可靠性 InteractionMapper.java 新增 findBySessionIds + 草稿查询 + 插入补列
可靠性 LiveNotificationService.java 删除 N+1 查询
可靠性 OpenClawServiceImpl.java 修复 streamChat sessionId bug
可靠性 PreviewTaskMapper.java 插入加 sourceDocId + findBySourceDocId
可靠性 DTO/InteractionPushDTO.java 新增 deadlineEpochMs
功能 HandRaiseService.java 新增 举手队列
功能 HandRaiseHandler.java 新增 举手 WS 端点
功能 TeachingMaterialGenerator.java 新增 AI 生成教学材料
功能 GenerateMaterialsRequest.java 新增 请求 DTO
功能 GenerateMaterialsResponse.java 新增 响应 DTO + 嵌套类型
功能 prompts/ppt-preview-generation.txt 新增 预习生成模板
功能 prompts/ppt-quiz-generation.txt 新增 试题生成模板
功能 DocumentController.java 新增 generate/save/drafts API
前端 live-session.ts 状态同步:举手队列 + 教师在线
前端 StudentLive.vue 举手 toggle + 倒计时修复 + 教师离线提示
前端 LiveDashboard.vue 举手队列面板
前端 KnowledgeBase.vue AI 生成面板 + 草稿列表 + 详情弹窗
前端 live.ts API 类型扩展
DB V8~V12 共 5 个迁移 见上文汇总