第三阶段:项目完善

3 阅读7分钟

第三阶段重构:统一接口响应与 Restful 规范化演进

1. 阶段核心目标与背景

在完成核心模块的 DDD 架构重构后,系统内部业务逻辑已高度内聚。但在接口交付层,仍存在前后端联调成本高、错误定位困难(依赖字符串如 msg: "未登录")、以及遗留 API 不规范(如 POST /devices/PageConditional)等工程问题。本阶段聚焦于接口层面的工程化改造,核心目标如下:

  • (1) 异常处理分层统一:彻底消灭 Controller 层臃肿的 try-catch 代码块,业务异常与系统级异常统一由全局/局部的 ExceptionHandler 拦截并转译为标准化 Rest 响应。
  • (2) 错误码语义标准化 (Error Code):废弃含糊不清的字符串错误提示,建立跨前端、后端、移动端可复用的强类型 ErrorCode 体系,提升联调效率与错误埋点分析能力。
  • (3) Restful 规范化与平滑迁移:落地符合现代 REST 语义的 API 设计。为避免业务中断,采取“双路径并行”的灰度策略,保留旧路径一个大版本,并通过标准的 HTTP 响应头(Deprecation Headers)输出警告,实现前端零停机平滑过渡。

2. 改造范围与涉及文件

2.1 后端 (Java 74.8%)

(1) 公共基础设施层 (Common):

  • /common/constant/ErrorCode.java (新增:统一错误码枚举字典)
  • /common/core/domain/Result.java (重构:支持基于 ErrorCode 的工厂方法构建)
  • /common/handler/GlobalExceptionHandler.java (新增:Spring @RestControllerAdvice 全局兜底)

(2) 业务系统层 (System - 振动设备与用户域):

  • /system/controller/DeviceController.java (路由改造:支持 /devices/query 与旧路径并行)
  • /system/controller/LoginController.java (路由改造:用户鉴权端点标准化)
  • /system/handler/DeviceExceptionHandler.java (新增:处理诸如“振动阈值设置不合法”等专有异常)
  • /system/handler/UserExceptionHandler.java (新增:处理账号封禁、密码连续试错等专有异常)
  • /system/utils/LoginCheckIntercept.java & LoginCheckFilter.java (优化:无权访问时抛出标准未登录异常码)

2.2 前端 (Vue 22.8% / JavaScript 2%)

  • vibration-web-portal/src/utils/request.js (核心逻辑:Axios 响应拦截器适配新错误码体系)
  • vibration-web-portal/src/views/device/DeviceManager.vue (视图改造:数据表格的分页查询接口平滑切换)

3. 主要改造内容详述

3.1 异常处理机制与错误码统一

3.1.1 建立 ErrorCode 错误码体系

在工业互联网场景中,设备状态与用户权限极为复杂。我们在 Result 封装体中引入了严格的 ErrorCode 枚举,取代了以往 Result.error("设备不存在") 的脆弱做法。错误码按业务域划分号段:

  • 通用基础 (1000+):
    • SYSTEM_ERROR(1000, "系统繁忙,请稍后再试")
    • INVALID_ARGUMENT(1001, "参数校验未通过")
  • 认证鉴权 (1100+):
    • NOT_LOGIN(1101, "访问凭证已过期或未登录")
    • LOGIN_FAILED(1102, "账号或密码错误")
    • USER_DISABLED(1103, "当前操作员账号已被冻结,请联系管理员")
  • 用户管理 (1200+):
    • USER_ACCOUNT_EXISTS(1201, "手机号/账号已被注册")
  • 设备与振动业务 (1300+):
    • DEVICE_VALIDATION_FAILED(1301, "设备参数校验失败(例:振动采样频率超限)")
    • DEVICE_OPERATION_FAILED(1302, "设备指令下发或状态流转失败")
3.1.2 异常处理分层收敛与 Controller 瘦身

此前 Controller 层为了处理保存设备时的唯一性冲突,充斥着大量的代码。重构后,Controller 只保留单行调用代码,异常统一上抛:

  • 全局域 (GlobalExceptionHandler): 负责兜底通用异常。例如,使用正则表达式拦截数据库层面的 Duplicate entry(如 DataIntegrityViolationException),精准映射为 1201 冲突业务码。
  • 业务域专项处理:
    • DeviceExceptionHandler: 专项拦截领域层抛出的 DeviceValidationException,将其转化为 Result.error(ErrorCode.DEVICE_VALIDATION_FAILED)
    • UserExceptionHandler: 专项拦截登录业务异常。
  • 无侵入鉴权拦截: 在 LoginCheckIntercept 中,当 JWT 校验失败时,直接通过 response.getWriter().write() 输出包含 ErrorCode.NOT_LOGIN 的标准 JSON,前端可无缝解析。

3.2 Restful 双路径并行策略

旧系统存在大量类似 POST /devices/PageConditional(动宾结构且带有大写字母)的反模式 API。本次采取 双路径并行、兼容一个大版本后下线 (预计 v2.5 下线) 的灰度迁移策略。

3.2.1 统一弃用响应头标准(Deprecated Headers)

我们在后端抽离了公共方法,在新旧两个 @PostMapping 中调用相同逻辑,但对旧路径额外注入 HTTP 标准弃用规范头。前端在抓包或控制台网络面板中会清晰看到警告:

HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: true
Sunset: 2026-06-30T23:59:59Z
Link: <https://api.vibration-cloud.com/v2/devices/query>; rel="successor-version"
Warning: 299 - "Deprecated API: /devices/PageConditional will be removed in v2.5"
3.2.2 核心接口路由映射表
业务模块新路径(标准 RESTful 规范)旧路径(仅作兼容期保留)状态与说明
设备 - 分页查询POST /devices/queryPOST /devices/PageConditional旧路径已注入 Deprecation 头
设备 - 缩略图上传POST /devices/{id}/imagePOST /devices/uploadImage将 ID 提取到 URL 路径参数中
设备 - 云端图库POST /devices/images/cloudPOST /devices/uploadImageToCloud语义化重构,旧路径保留
用户 - 新增注册POST /usersPOST /login/register遵循资源导向设计
用户 - 鉴权登录POST /users/loginPOST /login旧路径保留,将于 v2.5 移除

3.3 前端 (Vue) 最小兼容迁移

由于采用了兼容策略,前端的重构压力被极大地释放。前端组仅需对基础框架做一次低侵入式的兼容升级:

1. Axios 拦截器平滑适配 (request.js) 为了兼容旧版后端写死的 msg: "NOT_LOGIN" 和新版的 code: 1101,修改响应拦截器:

instance.interceptors.response.use(res => {
  const data = res.data;
  // 兼容新旧两套未登录标识,执行统一登出与路由重定向逻辑
  if (data.code === 1101 || data.msg === 'NOT_LOGIN') {
    store.dispatch('user/resetToken');
    router.push({ path: '/login', query: { redirect: router.currentRoute.fullPath } });
    return Promise.reject(new Error('凭证失效,请重新登录'));
  }
  // 业务级报错,统一走 ErrorCode
  if (data.code && data.code !== 1) {
    Message.error(data.msg || '操作失败');
    return Promise.reject(new Error(data.msg));
  }
  return data.data; // 正常返回脱壳后的数据
});

2. 视图层 API 替换 (DeviceManager.vue) 将设备大屏列表调用的老旧 API 平滑切换为新路径:

// 旧:import { getDevicePageConditional } from '@/api/device'
// 新:切换为符合 REST 规范的请求方法
import { queryDevicePage } from '@/api/device' 

// api/device.js 内部已更新为:
// export const queryDevicePage = (data) => request({ url: '/devices/query', method: 'post', data })

4. 阶段性回归与验收标准

A. 用户与认证体系回归

  1. 正常注册闭环: 模拟新操作员开户,请求 POST /users,校验落库情况并成功返回 code: 1
  2. 唯一性异常校验: 模拟高并发下注册重复账号(如手机号 13800000000),预期捕获约束异常并返回精准业务码 code: 1201
  3. 恶意登录拦截: 连续请求 POST /users/login 使用错误密码,预期返回 code: 1102;使用已被离职管理员标记状态的用户登录,预期返回 code: 1103
  4. 无感拦截验证: 清除浏览器 Cookie/LocalStore 中的 Token,访问 /devices/query,预期立刻被中间件拦截并返回 code: 1101,前端应触发自动跳转登录页。

B. 振动设备管理体系回归

  1. 查询引擎验证: 调用 POST /devices/query(附带复杂条件:泵类设备、运行状态、频段 10-500Hz),断言分页插件返回预期数据集。
  2. 文件流上传测试: 模拟向指定振动传感器(ID: DEV-8890)调用新路径 POST /devices/DEV-8890/image,验证本地文件 I/O 与数据库 URL 回写均成功。
  3. 领域规则边界测试: 构造非法设备载荷(例如:将报警阈值设定低于正常运行基线值),触发领域防腐层校验,预期全局拦截并返回 code: 1301 及明确的错误指导信息。

C. 生产环境容灾与平滑兼容验证

  1. 遗留流量监测: 通过 Postman 调用旧版移动端依赖的遗留路径(如 /devices/PageConditional),验证业务仍可正常闭环响应。
  2. 弃用声明核验: 检查上述遗留请求的 Header 中,是否成功输出了 Deprecation: trueSunset: 2026-06-30 警告标识,确保规范化要求已落实。