一、 用户登录注册 + 安全验证系统
1.0 用户系统基础
- 技术栈:Spring Security + JWT(无状态认证)。
- 核心流程 :
- 前端:用户输入用户名和密码。
- 后端 :
- 创建一个未认证的
UsernamePasswordAuthenticationToken。 - 交由
AuthenticationManager进行认证。 AuthenticationManager调用UserDetailsService.loadUserByUsername(username)从数据库加载用户信息(含加密密码)。- 使用
PasswordEncoder比对用户输入的明文密码与数据库中的加密密码。 - 认证成功后,生成一个已认证的
Authentication对象,并清空其中的密码。
- 创建一个未认证的
- JWT 生成:认证成功后,服务端使用用户 ID 生成一个 JWT Token 并返回给前端。
- 关键点 :
UserDetails是一个临时的、内存中的对象,用于封装从数据库查出的用户信息以供 Spring Security 认证流程使用,它本身不存储在数据库中。- JWT 的本质是一个加密后的用户 ID,用于无状态认证。
2.0 系统改造与前后端对接
- 后端实现 :
- 注册服务 :接收用户名、密码,使用
PasswordEncoder加密密码,将新用户存入数据库。 - 登录服务 (
LoginService):负责验证用户名/密码,并在成功后生成 JWT。 - 用户信息服务 (
InfoService):从 Spring Security 的安全上下文中获取当前已认证用户的信息(每次请求都通过 JWT 过滤器重新加载)。 - 配置 :需要配置
JwtUtil(用于创建和解析 JWT)、SecurityConfig(放行登录/注册等公开接口,并添加 JWT 过滤器)。
- 注册服务 :接收用户名、密码,使用
- 前端实现 (Vue) :
- 页面:分别实现登录页和注册页。
- 状态管理:使用 Vuex/Pinia 将登录后获得的 JWT Token 和用户信息保存在全局 Store 中,以便后续请求携带。
- 请求拦截:后续所有需要认证的 API 请求,都需要在请求头(Header)中携带 JWT Token。
二、 WebSocket 技术选型:实现游戏的持续通信
为什么选择 WebSocket?
- HTTP 的局限性:基于请求-响应模型,在应用层表现为半双工通信。无法满足游戏所需的"服务端主动推送"和"低延迟高频交互"。
- WebSocket 的优势 :
- 全双工通信:连接建立后,客户端和服务端可以随时、独立、并发地互相发送消息。
- 长连接:一次握手,持久保持连接,避免了 HTTP 频繁建立连接的开销。
- 高实时性:消息即时推送,毫秒级响应,完美契合"键盘输入 → 服务端同步计算 → 前端地图刷新"的游戏闭环。
WebSocket 实现要点
- 后端 :
- 配置:配置 WebSocket 的端点(Endpoint)。
- 建立连接 :处理客户端的连接请求,并维护一个
用户ID <-> WebSocket会话的映射表。 - 收发消息:接收来自前端的操作指令(如方向键),进行游戏逻辑计算,并将最新的游戏状态(如蛇的位置、地图信息)推送给对战双方。
- 前端 :
- 建立连接:在游戏开始时,与后端建立 WebSocket 连接。
- 发送消息:监听键盘事件,将操作指令通过 WebSocket 发送给后端。
- 接收消息:接收后端推送的游戏状态更新,并渲染到页面上。
三、 匹配系统
- 目的:为两个在线玩家寻找对手,开启一场对战。
- 核心逻辑 :
- 前端 :玩家点击"开始匹配"按钮,调用
startmatching(),向后端发起addgamer请求。 - 后端:维护一个"匹配池"。当有新的玩家加入时,检查池中是否有等待的玩家。如果有,则将两人配对成功。
- 异步性:匹配是一个异步过程,玩家可能需要等待一段时间,因此需要独立的匹配逻辑。
- 前端 :玩家点击"开始匹配"按钮,调用
- 简单实现:最简单的匹配方式就是 FIFO(先进先出)队列,将等待的用户 ID 存入队列,每来一个新用户就尝试与队首用户配对。
四、 对局记录表功能
- 目的:记录每一场对战的详细信息,用于后续的数据展示和游戏回放。
- 存储内容 :对局记录表应至少包含以下信息:
- 对战双方的用户 ID。
- 游戏地图(可用二维数组表示)。
- 双方蛇的初始位置。
- 双方玩家的所有操作序列。
- 对局结果(谁赢谁输)。
- 前端展示 :
- 分页列表:展示所有历史对局记录,支持分页查看。
- 详情展示:点击某条记录,可跳转到回放页面。
五、 回放功能
- 核心思想:利用对局记录表中的数据,在前端"重演"整场游戏。
- 实现步骤 :
- 页面跳转 :点击录像链接,跳转到一个类似 PK 对战的新页面,并传入
recordId。 - 数据加载 :根据
recordId从后端获取完整的对局记录数据。 - 初始化:在前端还原初始地图、两条蛇的初始位置和状态。
- 定时播放 :使用
setInterval函数,每隔 300ms(或其他合适的时间间隔)执行一步操作。- 在前 N-1 步,根据记录设置两条蛇的移动方向。
- 在第 N 步(最后一步),处理游戏结束逻辑(如将失败方的蛇变为灰色)。
- 页面跳转 :点击录像链接,跳转到一个类似 PK 对战的新页面,并传入
- 前端状态:回放功能主要在前端实现,需要定义一些全局变量或使用状态管理来控制播放逻辑。