02-需求分析与设计方案.md 17 KB

软件项目资源登记平台 — 需求分析与设计方案

一、需求分析

1.1 业务背景

随着企业数字化转型深入,团队在日常运营中会使用大量云资源和服务套餐(云服务器、云数据库、对象存储、域名、SSL 证书、CDN、短信包、邮件包等),这些资源具有以下特点:

  • 分散管理:资源由不同人员购买和管理,信息散落在个人手中,缺乏统一视图
  • 到期风险:资源到期如未续费会导致服务中断,影响线上业务
  • 归属不清:资源与项目之间的对应关系不明确,难以进行项目级成本核算
  • 成本盲区:缺乏全局费用统计,无法有效进行成本管控和优化

1.2 目标用户

角色 描述 核心诉求
管理员 系统管理员,拥有全部权限 统一管理平台所有资源和用户
普通用户 项目负责人/运维人员/开发人员 登记和管理自己负责的资源,接收到期提醒

1.3 功能需求

FR-01:用户认证与权限管理

  • FR-01-01:支持账号密码登录,登录成功后颁发 JWT Token
  • FR-01-02:支持修改个人密码(需验证原密码)
  • FR-01-03:区分管理员和普通用户两级角色
  • FR-01-04:管理员可管理所有用户(增删改查),普通用户无此权限

FR-02:资源管理

  • FR-02-01:支持资源的增删改查(逻辑删除)
  • FR-02-02:资源信息包含:名称、类型、服务商、账号信息、开通日期、到期日期、费用、计费周期、负责人、状态、备注
  • FR-02-03:支持按名称、类型、服务商、负责人、状态、到期天数等多维度筛选
  • FR-02-04:支持分页展示
  • FR-02-05:支持资源导出为 Excel 文件
  • FR-02-06:资源状态(使用中/即将到期/已过期/已停用)由系统自动维护

FR-03:项目管理

  • FR-03-01:支持项目的增删改查(逻辑删除)
  • FR-03-02:项目信息包含:名称、负责人、状态、备注
  • FR-03-03:项目详情页展示关联的资源列表
  • FR-03-04:支持在项目详情页关联/解除资源

FR-04:项目与资源关联

  • FR-04-01:一个资源可关联多个项目(多对多关系)
  • FR-04-02:在资源表单中可选择关联的项目(多选)
  • FR-04-03:在项目详情页可批量关联资源

FR-05:字典管理

  • FR-05-01:资源类型字典可增删改查,支持自定义排序
  • FR-05-02:服务商字典可增删改查
  • FR-05-03:字典变更实时生效,无需重启

FR-06:工作台

  • FR-06-01:展示项目总数、资源总数、即将到期数、已过期数
  • FR-06-02:展示需要关注的资源列表(即将到期 + 已过期,按到期日期升序)
  • FR-06-03:展示各资源类型的数量分布

FR-07:到期提醒

  • FR-07-01:系统每日定时扫描资源到期状态
  • FR-07-02:自动刷新资源状态字段(使用中→即将到期→已过期)
  • FR-07-03:分三个阶段发送邮件提醒:提前30天、提前7天、已过期
  • FR-07-04:同一资源同一阶段只发送一次提醒,避免重复骚扰
  • FR-07-05:已停用的资源不触发提醒
  • FR-07-06:提醒天数和 cron 表达式可配置

FR-08:费用统计

  • FR-08-01:按项目维度统计资源数量和总费用
  • FR-08-02:按资源类型维度统计资源数量和总费用

FR-09:操作日志

  • FR-09-01:记录资源、项目、用户等模块的关键操作(新增/编辑/删除/关联变更)
  • FR-09-02:日志包含操作人、操作模块、操作类型、操作对象、操作详情和时间
  • FR-09-03:支持分页查看操作日志

1.4 非功能需求

类别 要求
安全性 密码 BCrypt 加密存储;JWT 无状态认证;接口权限控制;CORS 跨域配置
性能 列表查询避免 N+1 问题,关联数据批量查询;分页查询减少单次数据量
可用性 统一响应格式和错误处理;前端统一拦截提示;表单参数校验
可扩展性 资源类型和服务商通过字典表管理,用户可自行扩展,无需修改代码
可维护性 前后端分离;分层架构清晰;Lombok 减少样板代码;MyBatis-Plus 简化数据访问
数据完整性 关键操作使用事务保证一致性;逻辑删除保留历史数据;唯一约束防止重复

二、系统设计方案

2.1 整体架构设计

采用经典的 前后端分离 + 分层架构 设计:

┌─────────────────────────────────────────┐
│           表现层 (Frontend)              │
│   Vue 3 SPA + Element Plus + Pinia      │
└─────────────────┬───────────────────────┘
                  │ REST API (JSON)
┌─────────────────▼───────────────────────┐
│           接口层 (Controller)            │
│   接收请求 → 参数校验 → 调用 Service     │
├─────────────────────────────────────────┤
│           业务层 (Service)               │
│   核心业务逻辑、事务管理、VO 组装         │
├─────────────────────────────────────────┤
│           持久层 (Mapper)                │
│   MyBatis-Plus BaseMapper 自动 CRUD      │
├─────────────────────────────────────────┤
│           数据层 (MySQL)                 │
│   8 张业务表 + 逻辑删除 + 唯一约束       │
└─────────────────────────────────────────┘

横切关注点:

  • 安全认证(JwtAuthenticationFilter)
  • 全局异常处理(GlobalExceptionHandler)
  • 操作日志记录(OperationLogService)

2.2 认证鉴权设计

登录流程:
  用户 → POST /auth/login {username, password}
       → Spring Security AuthenticationManager 校验
       → 校验通过 → JwtUtil.generateToken(userId, username) → 返回 Token
       → 校验失败 → 抛出 BadCredentialsException → 全局异常处理返回错误

请求鉴权流程:
  请求 → JwtAuthenticationFilter
       → 从 Authorization 头提取 Bearer Token
       → JwtUtil.parseToken() 验证有效性
       → 从数据库加载用户信息(含角色)
       → 设置 SecurityContext
       → SecurityConfig 根据路径规则判断权限
         - /auth/login → permitAll
         - /user/** → hasRole("ADMIN")
         - 其他 → authenticated

Token 设计:

  • 算法:HS256(HMAC-SHA256)
  • 有效期:24 小时(可配置)
  • 载荷:userId(自定义 claim)+ username(subject)
  • 前端存储:localStorage(简单可靠,适合内部系统)

2.3 数据模型设计

2.3.1 核心实体关系

Project ──M:N──> Resource
           │
    ProjectResource (中间表)

Resource ──N:1──> ResourceType (类型字典)
Resource ──N:1──> Provider (服务商字典)
Resource ──N:1──> SysUser (负责人)
Project  ──N:1──> SysUser (负责人)
Resource ──1:N──> ExpireNotifyLog (提醒记录)
SysUser  ──1:N──> OperationLog (操作日志)

2.3.2 关键字段设计决策

设计决策 选择 原因
资源状态存储 冗余 status 字段 避免每次查询都计算到期状态,支持直接按状态筛选和索引
项目-资源关系 独立中间表 多对多关系的标准实现,支持双向查询
到期提醒防重 唯一约束+代码查重 数据库层面兜底 + 应用层面先查后插,双重保障
逻辑删除 deleted 字段 保留历史数据,支持数据恢复,MyBatis-Plus @TableLogic 自动过滤
密码存储 BCrypt Spring Security 默认方案,自带盐值,安全性高
费用字段 DECIMAL(12,2) 精确的货币计算,避免浮点精度问题

2.4 核心业务流程设计

2.4.1 资源创建/编辑流程

用户提交表单
  → Controller 接收 ResourceDTO(含 projectIds 列表)
  → Service.saveOrUpdate()
    → 判断是新增还是编辑
    → 保存 Resource 基本信息
    → 维护项目关联:
      1. 删除该资源的所有旧关联 (DELETE FROM project_resource WHERE resource_id = ?)
      2. 遍历 projectIds,逐条插入新关联
    → 记录操作日志
  → 事务提交

设计考量:采用"先删后插"策略维护关联关系,逻辑简单、不易出现脏数据,适合数据量不大的场景。

2.4.2 到期提醒定时任务流程

@Scheduled(cron = "0 0 8 * * ?")
  → Step 1: refreshExpireStatus()
    → 查询所有非停用资源
    → 根据到期日期计算新状态
    → 状态变化时更新数据库

  → Step 2: 邮件提醒扫描
    → 查询所有有到期日期且非停用的资源
    → 遍历每个资源:
      → 计算距到期天数
      → 判断所处阶段(>30天:不提醒 / ≤30天:stage1 / ≤7天:stage2 / <0:stage3)
      → 查询 expire_notify_log 是否已发送该阶段提醒
      → 未发送 → 查询负责人邮箱 → 发送邮件 → 写入日志记录
    → 输出发送统计

邮件策略: | 阶段 | 条件 | 邮件标题样式 | 发送次数 | | --------- | -------------- | ------------------------------------- | -------- | | stage=1 | 距到期≤30天 | 【资源到期提醒】xxx 将在N天后到期 | 1次 | | stage=2 | 距到期≤7天 | 【紧急】资源 xxx 即将到期,仅剩N天 | 1次 | | stage=3 | 已过期(天数<0) | 【已过期】资源 xxx 已到期,请尽快处理 | 1次 |

2.4.3 数据查询与 VO 组装流程

Controller 接收查询参数
  → Service 构建 LambdaQueryWrapper
  → Mapper.selectPage() 分页查询 Resource 实体
  → assembleVOList() 批量组装 VO:
    1. 收集所有 typeId、providerId、ownerId、resourceId
    2. 批量查询 ResourceType → Map<id, name>
    3. 批量查询 Provider → Map<id, name>
    4. 批量查询 SysUser → Map<id, realName>
    5. 批量查询 ProjectResource → Map<resourceId, List<projectId>>
    6. 批量查询 Project → Map<id, name>
    7. 遍历 Resource 列表,填充 VO 各字段
  → 返回 Page<ResourceVO>

性能考量:将 N+1 查询转化为 5 次批量查询,极大减少数据库交互次数。

2.5 前端架构设计

2.5.1 目录结构

frontend/src/
├── api/            # API 接口封装(按业务模块拆分)
│   ├── request.js  # Axios 实例 + 拦截器
│   ├── auth.js     # 登录、用户信息、密码修改
│   ├── dashboard.js
│   ├── resource.js
│   ├── project.js
│   ├── dict.js
│   ├── user.js
│   └── log.js
├── layout/         # 全局布局组件(侧边栏 + 顶部栏)
├── router/         # 路由配置 + 导航守卫
├── store/          # Pinia 状态管理(用户状态)
├── views/          # 页面组件(按业务模块组织)
│   ├── Dashboard.vue
│   ├── Login.vue
│   ├── CostStat.vue
│   ├── resource/   # 资源管理
│   ├── project/    # 项目管理
│   ├── dict/       # 字典管理
│   └── system/     # 系统管理(用户 + 日志)
├── styles/         # 全局样式变量
└── components/     # 公共组件

2.5.2 组件设计模式

  • 页面组件:每个页面一个 .vue 文件,使用 <script setup> 语法
  • 表单弹窗:独立为子组件(如 ResourceForm.vue),通过 v-model:visible 控制显隐,@saved 事件通知父组件刷新
  • 列表页模式:筛选表单 + 工具栏 + 数据表格 + 分页器,统一交互范式

2.5.3 状态管理策略

仅使用 Pinia 管理用户登录状态(Token + 用户信息),其他页面数据通过组件内部 ref/reactive + API 调用管理,避免过度使用全局状态。

2.6 安全设计

安全措施 实现方式
密码安全 BCrypt 加密存储,不存储明文/可逆密文
身份认证 JWT 无状态 Token,每次请求验证有效性
接口权限 Spring Security 路径规则 + 角色校验
跨域安全 CORS 配置允许指定来源,支持携带凭证
CSRF 防护 无状态 API(JWT)禁用 CSRF(不依赖 Cookie)
敏感信息 资源表不存储密码,仅存储账号/控制台链接
参数校验 Jakarta Validation 注解校验 + 全局异常处理

2.7 扩展性设计

扩展点 设计方案
资源类型 字典表管理,用户可通过界面增删,无需改代码
服务商 字典表管理,同上
提醒天数 application.yml 配置项,修改后重启生效
定时任务频率 cron 表达式可配置
Token 有效期 application.yml 配置项
筛选条件 基于 MyBatis-Plus LambdaQueryWrapper 条件组装,易于扩展

三、已知局限与改进方向

3.1 当前局限

  1. 权限粒度:仅管理员/普通用户两级,普通用户可查看所有数据,未实现"只能管理自己负责的资源"
  2. 数据加载:前端的项目/资源下拉选择为一次性全量加载,数据量大时性能可能不佳
  3. 敏感配置:邮箱密码、数据库密码等直接写在配置文件中,存在安全风险
  4. 测试覆盖:目前无自动化测试
  5. 资源状态刷新:依赖定时任务,存在最长24小时的延迟

3.2 建议改进方向

优先级 改进项 方案
高 细粒度数据权限 增加"只查看自己负责的"筛选逻辑,基于 ownerId 过滤
高 敏感配置外部化 使用环境变量或配置中心(如 Nacos)管理密码和密钥
中 远程搜索下拉 将全量加载改为远程搜索 + 分页加载
中 接口自动化测试 使用 JUnit 5 + MockMvc 对核心接口编写集成测试
中 状态实时刷新 在资源列表查询时实时计算状态,或缩短定时任务间隔
低 操作日志增强 使用 AOP 切面自动记录日志,减少 Service 中的手动调用
低 文件上传管理 支持上传合同/发票等附件,与资源关联
低 数据备份与恢复 定期数据库备份,支持导出全量数据为 JSON/CSV
低 多租户支持 如需对外提供服务,可增加租户隔离机制