Skip to content

资源库引用与删除设计 ​

目标与边界 ​

sys_media 是 system 模块统一上传的资源目录。配置及业务表可以引用同一资源,列表应展示实际引用位置,删除应拒绝仍在使用的资源。用户头像现为文字与背景色,不引用资源。图片、视频、文档等文件类型共用这套引用规则,文件类型只影响上传限制与预览方式。

这套保护针对登记在 sys_media 的 URL。外部 URL 不进入引用索引,也不由资源库删除。业务来源若没有接入登记或检查器,系统无法凭 URL 自动发现它;接入责任由保存该业务数据的模块承担。

数据模型 ​

  • sys_media.status:active 可引用;deleting 已通过引用检查,等待对象存储及数据库记录清理。删除对象失败时保留该状态与记录,管理员可重试删除。
  • sys_media_reference:一条资源在一个来源字段中的引用一行。media_id + source_type + source_id + field_key 唯一;label 用于资源库展示位置。一个字段引用多份资源时有多行,顺序仍由业务字段保存,引用表不承担排序。
  • 历史迁移曾将配置值和图片头像回填;新迁移移除旧头像引用。配置可能保存单 URL、JSON 数组或 HTML,回填使用完整 URL 子串保守匹配,宁可多保留引用,也不能漏删保护。

读取与校验 ​

资源列表按页取 sys_media 后,批量合并引用表与全部 MediaReferenceChecker 的结果,并去重显示 label。删除对目标资源执行同一检查。检查器抛异常时列表查询失败、删除中止,不会把检查失败当成“没有引用”。内置检查器覆盖当前配置值,兼容历史记录或索引修复期间的数据。

业务模块可以提供 MediaReferenceChecker Bean,返回 MediaReferenceLocation(url, sourceType, sourceId, field, label)。检查器适合查询历史表和迁移过渡;批量接收 URL,应避免每个文件单独全表扫描。需要在数据库、外部服务等来源查询时,查询失败应抛出异常。多个检查器会组装执行,任一来源命中就禁止删除。

写入与删除时序 ​

来源模块在保存业务字段的同一事务内调用 MediaReferenceService.replace(sourceType, sourceId, field, label, urls),传入该字段保存后的完整 URL 集合;删除来源时传空集合。这个 API 在 weiran-system-api,业务模块只依赖该 API,不依赖 system 的实现层。方法要求已有事务,没有事务会失败。配置的仓储写入已内置同步登记。

replace 先找出旧引用和新引用所涉及的资源,按 ID 顺序锁定 sys_media 行,再替换来源字段的引用。若新资源已在 deleting 状态,整个来源保存事务回滚。删除资源时,在事务中执行各检查器、锁定同一资源行、再次核对登记引用,然后标记 deleting;事务提交后删除存储对象,再用新事务删除 sys_media 记录。这样,已接入同步登记的来源在并发保存与删除时不会越过删除检查。检查器为未同步登记的来源提供实时检查,但仅靠检查器无法防止检查后发生的新写入;此类来源应尽快接入 replace。

示例(应用服务方法已经由 @Transactional 包围):

java
businessRepository.save(record);
mediaReferenceService.replace(
        "article", String.valueOf(record.id()), "attachments", "文章附件:" + record.title(), record.attachmentUrls());

来源类型和字段名应稳定,来源 ID 使用稳定的字符串标识。每次调用必须传完整集合,不能只传增量。更新显示名称时也调用一次,以更新 label。页面上传成功仅创建 sys_media,用户最终保存业务表后才产生引用;移除文件并保存会清除引用,之后才能从资源库删除该文件。

接入与运维 ​

  1. 新的业务表增加文件字段时,在保存、清空和删除记录的事务内调用 replace。对于富文本,提取其中由资源库上传的 URL;外部链接无需登记。
  2. 有历史数据的模块先做一次回填,并注册实时检查器作为过渡;校对资源库列表的引用位置后再撤除检查器。
  3. 存储删除失败时保留 deleting 行;排除存储故障后重试删除。不要直接删除引用表行或手工把 deleting 改回 active 来绕过校验。
  4. 业务来源接入情况记录在模块文档。当前通用扩展点已经提供,尚未接入的业务模块仍有漏检风险。

Java 21 · React · Spring Boot