个人站点

第 8 / 8 篇

整理于 · 9 分钟

九月重构修正了哪些边界

有限重构中的接口约定、页面状态和交易验证

贯穿项目的约定 本篇涉及 3 条

贯穿项目的约定

  1. 课时属于具体课程,班级、课次与教室容量分别判断。

    查看规则说明
  2. 各角色只在授权范围内操作,家长代办以确认绑定为前提。

    本篇涉及 查看规则说明
  3. 账号、关系、教学与订单各有状态,一处变化不代替另一处判断。

    本篇涉及 查看规则说明
  4. 课程课时、订单金额和钱包资金分开,费用变化保留业务依据。

    本篇涉及 查看规则说明

本篇如何落实

限定范围修订接口、复杂页面与交易链路,迟到响应先核对当前上下文;合成交易验证保留未完成门禁和歧义处理边界。

在初期部署与演示准备之后,代码中仍有需要处理的边界:部分接口直接返回数据库实体,复杂页面切换上下文时可能混入旧数据,而关闭弹窗并不意味着后端事务已经终止。

2026 年 9 月,项目围绕身份、前后端契约、复杂页面状态与数据库事务展开有限重构。它保留原技术栈,按限定入口修正行为并补充验证。

1. 有限重构的目标:沿用技术栈,修正接口与状态

本轮继续使用 Vue 3 + Element Plus + PiniaSpring Boot 2.7 + MyBatis-Plus

工作集中在四个方面:

  1. 接口契约:统一迁移入口的请求参数校验与读取响应 DTO;
  2. 状态机重构:重塑仪表盘、课程中心、订单页、课次详情四大复杂页面的交互生命周期;
  3. 消除竞争隐患:治理弹窗关闭与在途请求(In-Flight Requests)脱节引发的重复提交;
  4. 真实数据库事务验收:在隔离的真实 MySQL 环境下验证跨模块死锁防护与数据不变量。
前端治理 Vue 3 / Pinia
四大复杂页面状态机解耦
相关动作的在途提交状态与弹窗分离
迟到响应 Late Responses 上下文丢弃
双向约束
前后端契约边界 Contracts
迁移入口的请求校验显式身份 / 参数检查 / HTTP 状态码
迁移入口的读取响应限制返回字段 / 区分标识含义
双向约束
后端治理 Spring Boot / MySQL
相关交易共享行锁的相对顺序
限定路由的业务错误与脱敏 500
隔离 MySQL 合成场景事务验证
契约边界夹在两侧治理之间,任一侧的改动都要过它

2. 前后端契约:请求校验与读取响应

2.1 读取 DTO:明确返回字段与标识

在早期代码中,Controller 常常直接将数据库持久化实体(Entity)序列化为 JSON 返回给前端。这导致了严重的安全与概念混乱:

  • 敏感字段泄露:部分用户信息接口曾无意中将密码哈希或内部凭据返回给前端;
  • ID 概念混淆:前端难以分清返回的 ID 究竟是家长账号 ID(userId)、绑定关系 ID(relationId),还是排课课次 ID(scheduleId)与课程开班 ID(courseInstanceId)。

迁移范围内的读取接口采用专用响应 DTO:

  • 移除相关响应中的密码与内部凭据字段;
  • 显式区分关系标识与用户主体标识;
  • 对于数据暂缺状态(如学生未录入姓名),明确返回待核对提示状态,坚决不用虚假的默认字符串掩盖数据缺失。

2.2 请求与错误契约:规范 HTTP 语义

早期接口习惯用 HTTP 200 状态码包裹带有 code: 500 的业务异常。这种“伪成功”给前端拦截器与网络监控带来了极大困扰。

已迁移入口按以下 HTTP 语义处理错误:

  • 400:请求字段格式不合法或缺失必填项;
  • 403:跨权限或越权访问他人子女记录;
  • 404:目标课程、课次或订单不存在;
  • 409:状态冲突(如名额已被他人抢占、订单已超时、已存在相同绑定关系);
  • 500:限定迁移路由中的未知服务端异常,对外返回固定提示,避免暴露原始异常细节。

3. 四大复杂页面的状态治理

3.1 仪表盘:各区域独立重试与图表生命周期

管理员与教师仪表盘包含多个异构数据卡片(营收统计、排课网格、AI 建议、出勤趋势)。

重构让相关卡片分别管理查询和错误状态,失败区域提供重试;同时在组件卸载时销毁 ECharts 实例。局部失败和图表清理有了对应处理,但这不等于所有网络异常或内存问题都已排除。

3.2 课程中心与订单页:单次筛选与上下文绑定

  • 课程中心:筛选改为回车或点击按钮后显式提交;标签在内部维护为数组,在 API 边界序列化。这与输入后按时间延迟触发的防抖不同;
  • 订单页:每张订单卡片独立维护自己的操作上下文,支付弹窗中的待付金额与倒计时严格绑定当前选中的单据,防止在多订单切换时串改支付金额。

3.3 课次详情:可操作性的可读状态

对于调课、请假与评价按钮,系统显示不可操作的原因,例如课次未结束或不满足请假规则,让禁用状态有可读解释。

4. 关键交互隐患修复:在途请求锁与弹窗解耦

本轮处理的一类交互问题,是把在途提交状态错误地绑定到弹窗可见性。风险过程如下:

  1. 用户在付款弹窗中点击“确认支付”,前端加锁并向后端发送扣款请求;
  2. 用户在等待网络响应的过程中关闭了弹窗;
  3. 旧系统缺陷:前端在弹窗关闭回调中顺手将“提交锁”释放了,但此时后端的扣款请求依然在路上;
  4. 用户重新打开弹窗后再次提交,就可能发出重复支付请求。请求重复不等于已发生两次实际扣款,后端仍需检查状态。

9 月重构把相关动作的在途提交状态从弹窗状态中分离:

  • 请求未结束时,关闭弹窗不清除该动作的提交保护;
  • 重新打开相关弹窗时,按钮根据在途状态限制再次提交;
  • 页面或业务对象变化后,响应处理会核对原请求上下文,避免旧数据和提示写入新的上下文。

这些是对应页面和动作的保护,并不是覆盖全系统的业务锁,也不能代替后端事务校验。

5. 本轮验证的范围与结果

9 月事务验证在独立隔离的 MySQL 9.3 中使用原有表结构和合成数据。记录包括:

  • 跨模块事务:28 个指定场景和 22 项双连接检查通过,覆盖相关锁等待、竞争与回滚;
  • 数据不变量:12 项断言检查测试状态下的余额、名额与流水关系;
  • 四角色 API 流程:169 项 API 断言通过,使用的是测试角色与合成数据。

验证留下的边界

这些数字属于指定测试批次,存在覆盖重叠,不能相加成全系统验收数量。记录还保留以下边界:

  1. 契约迁移未覆盖全系统:成绩模块的非法孩子查询仍可能返回旧的 HTTP 200 / code: 500;历史报名同秒歧义继续拒绝处理,订单缺少学员姓名时显示待核对。
  2. 依赖检查尚未全部闭合:自动依赖门禁仍为待完成,人工检查仅确认限定范围内对齐。
  3. 验证范围有限:未迁移模块、既有业务库兼容、真实第三方支付和全站移动端未纳入本轮验收;验证码与第三方支付仍有模拟能力。
  4. 展示状态:体验环境已清理,在线展示安排已取消。180 个图位是清单,不代表截图已采集,也不是当前在线服务的证据。

本轮能确认的是:限定入口的接口、状态和交易规则经过修订,并留下了对应验证。继续接入或展示时,应沿用这些范围说明,不能把有限重构完成扩写为全系统已经通过生产验收。