Files
ccdi/docs/superpowers/specs/2026-05-06-bank-upload-original-filename-design.md

6.0 KiB
Raw Blame History

上传流水文件原始文件名保持设计

背景

项目详情的“上传数据”页支持批量上传流水文件。当前前端提交文件时保留了浏览器选择文件的原始文件名,但后端为了异步处理,会先把文件保存为带有批次号、序号和时间戳的临时文件名。异步任务再把这个临时文件对象转传给流水分析平台,导致流水分析平台上传接口收到的 multipart 文件名不是用户初始上传的文件名。

同时,后端在查询流水分析平台文件状态后,会用平台返回的 uploadFileNamedownloadFileName 覆盖本系统上传记录 ccdi_file_upload_record.file_name,页面列表读取该字段展示文件名,因此页面展示名也可能与初始上传文件名不一致。

目标

  • 新上传流水文件时,页面展示的文件名必须保持用户初始上传文件名。
  • 调用流水分析平台上传文件接口时multipart 文件 part 的 filename 必须保持用户初始上传文件名。
  • 临时文件仍需保持唯一命名,避免批量上传、同名文件或并发上传互相覆盖。
  • 本次只处理“上传本地流水文件”链路,不改变“拉取本行信息”链路的现有文件名展示与状态处理行为。
  • 历史已上传记录不做批量回改。

非目标

  • 不修改历史上传记录的文件名。
  • 不调整上传入口、文件格式限制、文件大小限制、异步任务调度和解析轮询规则。
  • 不新增数据库字段。
  • 不改变流水分析平台接口地址、请求参数名和响应解析口径。
  • 不改变“拉取本行信息”生成的上传记录文件名规则。

现状链路

  1. 前端 UploadData.vueselectedFiles.map((f) => f.raw) 传给 batchUploadFiles
  2. ccdiProjectUpload.js 使用 FormData.append("files", file) 上传,浏览器侧仍保留原始文件名。
  3. CcdiFileUploadController.batchUpload 通过 MultipartFile.getOriginalFilename() 校验格式。
  4. CcdiFileUploadServiceImpl.batchUploadFiles 保存记录时写入原始文件名,但临时文件路径使用 batchId_index_timestamp_originalFilename
  5. processFileAsync 读取临时文件并调用 lsfxClient.uploadFile(lsfxProjectId, file)
  6. LsfxAnalysisClient.uploadFileHttpUtil.uploadFile 只接收 File,最终用 FileSystemResource 发送文件multipart filename 来自临时文件名。
  7. 查询文件上传状态后,processRecordAfterLogIdReady 使用平台返回文件名覆盖 record.fileName

设计方案

后端上传转发

保留当前临时文件唯一命名方式,避免同名文件覆盖。异步处理时以 CcdiFileUploadRecord.fileName 作为原始文件名来源,将“临时文件内容”和“原始文件名”一起传给流水分析客户端。

LsfxAnalysisClient.uploadFile 增加可指定上传文件名的能力。对项目上传流水链路,调用新签名并传入原始文件名;测试 Controller 或其他调用方如果不传原始文件名,可继续使用现有文件名语义。

HttpUtil.uploadFile 增加对“文件内容 + 指定 filename”的 multipart 资源包装。发送时仍使用参数名 files,但文件 part 的 filename 使用原始文件名,而不是临时文件名。

上传记录文件名

“上传本地流水文件”链路中的 ccdi_file_upload_record.file_name 只记录本系统初始上传文件名。查询流水分析平台状态后,该链路不再用 uploadFileNamedownloadFileName 覆盖该字段。

平台返回的文件大小仍可继续更新到 file_size,解析状态、主体名称、账号、错误信息等字段保持现有处理方式。

当前状态后处理逻辑会被本地上传和“拉取本行信息”复用。实现时需要在调用或方法参数上区分来源:本地上传链路保留初始文件名;拉取本行信息链路保持现有行为,继续按当前规则处理平台返回文件名。

前端展示

前端无需改造。上传记录列表继续展示后端返回的 fileName。由于本地上传链路后端不再覆盖该字段,新上传记录从创建、处理中、成功或失败状态都会展示初始上传文件名。

数据流

用户选择文件: 银行流水A.xlsx
  -> 前端 FormData files: filename=银行流水A.xlsx
  -> 后端 MultipartFile originalFilename=银行流水A.xlsx
  -> 本地临时文件: batchId_0_timestamp_银行流水A.xlsx
  -> 上传记录 file_name=银行流水A.xlsx
  -> 流水分析平台 multipart files: filename=银行流水A.xlsx
  -> 页面上传记录 fileName=银行流水A.xlsx

错误处理

  • 原始文件名为空时,沿用 Controller 现有“文件名不能为空”校验。
  • 临时文件不存在、上传失败、解析失败时,沿用现有失败状态和错误信息记录方式。
  • 指定原始文件名只影响 multipart filename不影响临时文件读取和异常处理。

测试计划

  1. 后端单测或轻量验证覆盖 multipart 资源 filename传入临时文件和原始文件名后上传请求中的文件名应为原始文件名。
  2. 后端链路测试覆盖 CcdiFileUploadServiceImpl:创建上传记录后,异步上传调用使用 record.fileName 作为原始文件名。
  3. 状态处理测试覆盖平台返回 uploadFileName/downloadFileName 与初始文件名不一致时,本系统记录仍保持初始文件名。
  4. 拉取本行信息链路回归:本次改动不改变其现有文件名展示与状态处理行为。
  5. 真实页面测试:在项目详情“上传数据”页上传一个文件名带中文的流水文件,核对页面上传记录展示初始文件名,并通过日志或 mock 接收端确认流水分析平台上传接口收到的 filename 为初始文件名。

影响范围

  • ccdi-project:上传流水异步处理链路。
  • ccdi-lsfx:流水分析平台上传客户端和 multipart 工具。
  • ruoyi-ui:无需源码改动,仅做真实页面验证。
  • 数据库:无需结构变更,历史数据不回改。