后端文件上传数据丢失问题.md 8.3 KB

后端文件上传数据丢失问题

发现日期: 2025-01-24
问题模块: 文件上传/OSS服务
影响范围: 所有使用附件上传的业务模块
严重程度: ⚠️ 中等(影响用户体验,但有前端兜底)


问题描述

后端在保存文件时丢失了真实的文件名和扩展名信息,导致前端回显时无法正确识别文件类型。

问题表现

从 /resource/oss/listByIds/{ossIds} API 返回的数据中:

{
    ossId: "1981738218223079425",
    originalName: "12038a7c-48bd-4978-bcbb-1119a201a6e9",  // ❌ UUID,不是用户上传的真实文件名
    fileSuffix: "9",                                        // ❌ 数字字符,不是真实扩展名(应该是 jpg/png 等)
    fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139", // ❌ 没有扩展名
    url: "/resource/oss/download/1981738218223079425"
}

期望的数据格式

{
    ossId: "1981738218223079425",
    originalName: "违纪现场照片.jpg",     // ✅ 用户上传时的真实文件名
    fileSuffix: "jpg",                    // ✅ 真实的文件扩展名
    fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139.jpg", // ✅ 包含扩展名
    url: "/resource/oss/download/1981738218223079425"
}

问题分析

可能的原因

  1. 文件上传时未保存原始文件名

    • 上传接口 /resource/oss/upload 可能未正确提取文件名
    • originalName 字段被UUID覆盖
  2. 扩展名提取错误

    • fileSuffix 字段提取逻辑有误
    • 从文件路径末尾提取了一个字符(如 9、e、d)而不是真实扩展名
  3. 数据库保存逻辑问题

    • sys_oss 表中的字段未正确保存
    • 可能是某个字段映射错误

影响的业务场景

  • ✅ 新增上传:正常工作(文件可以上传)
  • ❌ 回显展示:文件类型识别错误,图片无法正常显示
  • ❌ 下载功能:下载的文件名显示为UUID,用户体验差
  • ❌ 文件管理:管理员无法识别文件内容

复现步骤

  1. 在移动端进入"宿舍卫生检查"模块
  2. 点击"录入违纪",上传一张图片(如 photo.jpg)
  3. 保存违纪记录
  4. 刷新页面或重新进入
  5. 点击"编辑"查看违纪记录
  6. 问题:附件无法显示为图片,文件名显示为UUID

调试信息

前端上传请求

// 调用上传接口
POST /resource/oss/upload
Content-Type: multipart/form-data

// FormData:
file: [Blob] photo.jpg
bizType: "dorm_violation_attachment"

后端返回(上传成功)

{
    code: 200,
    data: {
        ossId: "1981738218223079425",
        url: "/resource/oss/download/1981738218223079425",
        fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139"  // ⚠️ 缺少扩展名
    }
}

后端返回(回显查询)

// GET /resource/oss/listByIds/1981738218223079425
{
    code: 200,
    data: [{
        ossId: "1981738218223079425",
        originalName: "12038a7c-48bd-4978-bcbb-1119a201a6e9",  // ❌ UUID
        fileSuffix: "9",                                        // ❌ 错误
        fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139",
        url: "/resource/oss/download/1981738218223079425"
    }]
}

建议的修复方案

方案1:修复上传接口(推荐)⭐

修改文件:backend/src/main/java/com/ruoyi/resource/controller/SysOssController.java

修复点:

  1. 上传时正确提取并保存 originalName(用户上传的文件名)
  2. 正确提取文件扩展名保存到 fileSuffix
  3. 保存到OSS的文件名应包含扩展名
@PostMapping("/upload")
public R<SysOss> upload(@RequestParam("file") MultipartFile file, 
                        @RequestParam(required = false) String bizType) {
    // 获取原始文件名
    String originalFilename = file.getOriginalFilename();
    
    // 提取真实扩展名
    String extension = "";
    if (originalFilename != null && originalFilename.contains(".")) {
        extension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
    }
    
    // 生成OSS文件名(包含扩展名)
    String ossFileName = generateOssFileName() + "." + extension;
    
    // 保存到数据库
    SysOss oss = new SysOss();
    oss.setOriginalName(originalFilename);  // ✅ 保存真实文件名
    oss.setFileSuffix(extension);           // ✅ 保存真实扩展名
    oss.setFileName(ossFileName);           // ✅ 包含扩展名的OSS文件名
    
    // ... 其他逻辑
}

方案2:修复查询接口

修改文件:backend/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java

修复点:

  1. 从数据库正确读取 originalName 和 fileSuffix
  2. 确保返回的VO类包含正确的字段值
public List<SysOssVo> listByIds(String ossIds) {
    // ... 查询逻辑 ...
    
    List<SysOssVo> voList = new ArrayList<>();
    for (SysOss oss : ossList) {
        SysOssVo vo = new SysOssVo();
        vo.setOssId(oss.getOssId());
        vo.setOriginalName(oss.getOriginalName());  // ✅ 确保读取正确
        vo.setFileSuffix(oss.getFileSuffix());      // ✅ 确保读取正确
        vo.setFileName(oss.getFileName());
        vo.setUrl(oss.getUrl());
        voList.add(vo);
    }
    
    return voList;
}

方案3:数据库表结构检查

检查表:sys_oss

需要确认的字段:

-- 检查字段定义
SHOW COLUMNS FROM sys_oss LIKE '%name%';
SHOW COLUMNS FROM sys_oss LIKE '%suffix%';

-- 检查数据示例
SELECT oss_id, original_name, file_suffix, file_name 
FROM sys_oss 
WHERE oss_id = '1981738218223079425';

期望的字段定义:

  • original_name VARCHAR(255) - 用户上传的原始文件名
  • file_suffix VARCHAR(10) - 文件扩展名(jpg/png/pdf等)
  • file_name VARCHAR(500) - OSS中的文件路径(应包含扩展名)

临时解决方案(前端兜底)

已实施:在 ViolationRecordDialog.vue 中添加了兜底逻辑

// 检测 fileSuffix 是否为有效扩展名
if (item.fileSuffix && item.fileSuffix.length <= 5 && /^[a-zA-Z]+$/.test(item.fileSuffix)) {
    // 使用 fileSuffix
    realExtension = item.fileSuffix.toLowerCase();
    fileType = this.getFileTypeBySuffix(realExtension);
} else {
    // 默认按图片处理(违纪证明材料大概率是图片)
    realExtension = 'jpg';
    fullFileName = `违纪证明_${timestamp + index}.jpg`;
    fileType = 'image/jpeg';
}

局限性:

  • ✅ 可以临时解决图片回显问题
  • ❌ 无法恢复真实的文件名
  • ❌ 非图片文件可能被错误识别
  • ❌ 用户体验不佳

验证方法

1. 后端修复后的验证

步骤:

  1. 上传一张图片 test.jpg
  2. 调用 /resource/oss/listByIds/{ossId} 查询
  3. 检查返回数据:
    • originalName 应该是 test.jpg
    • fileSuffix 应该是 jpg
    • fileName 应该包含 .jpg 扩展名

期望日志:

违纪记录:原始数据 - originalName=test.jpg, fileSuffix=jpg, fileName=2025/10/24/xxx.jpg
违纪记录:最终文件名=test.jpg, 扩展名=jpg, 文件类型=image/jpeg

2. 前端验证

步骤:

  1. 上传图片后编辑违纪记录
  2. 检查附件回显是否正常
  3. 检查文件名是否正确显示

期望结果:

  • ✅ 图片正常显示(不是灰白背景)
  • ✅ 文件名显示为真实文件名(不是UUID)
  • ✅ 下载文件名正确

相关文件

后端:

  • backend/src/main/java/com/ruoyi/resource/controller/SysOssController.java
  • backend/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java
  • backend/src/main/java/com/ruoyi/resource/domain/vo/SysOssVo.java
  • backend/src/main/java/com/ruoyi/resource/domain/SysOss.java

前端:

  • mobile/src/pages/xgss/wsjc/components/ViolationRecordDialog.vue(已添加兜底逻辑)

数据库:

  • sys_oss 表

优先级和影响

优先级: P2(中等)

影响评估:

  • 用户体验: ⬇️ 下降(文件名显示为UUID,无法识别内容)
  • 功能可用性: ✅ 正常(有前端兜底,基本功能可用)
  • 数据完整性: ⚠️ 受影响(历史数据无法恢复真实文件名)

建议处理时间: 2周内修复


创建时间: 2025-01-24
创建人: Cursor AI
状态: 🔴 待修复