提交代码
This commit is contained in:
1 parent
e97c97aa0b
commit
1b117de6cf
3 files changed
+1246
-102
No files matched your search
@@ -0,0 +1,300 @@
|
||||
# 后端文件上传数据丢失问题
|
||||
|
||||
**发现日期**: 2025-01-24
|
||||
**问题模块**: 文件上传/OSS服务
|
||||
**影响范围**: 所有使用附件上传的业务模块
|
||||
**严重程度**: ⚠️ 中等(影响用户体验,但有前端兜底)
|
||||
|
||||
---
|
||||
|
||||
## 问题描述
|
||||
|
||||
后端在保存文件时丢失了真实的文件名和扩展名信息,导致前端回显时无法正确识别文件类型。
|
||||
|
||||
### 问题表现
|
||||
|
||||
从 `/resource/oss/listByIds/{ossIds}` API 返回的数据中:
|
||||
|
||||
```javascript
|
||||
{
|
||||
ossId: "1981738218223079425",
|
||||
originalName: "12038a7c-48bd-4978-bcbb-1119a201a6e9", // ❌ UUID,不是用户上传的真实文件名
|
||||
fileSuffix: "9", // ❌ 数字字符,不是真实扩展名(应该是 jpg/png 等)
|
||||
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139", // ❌ 没有扩展名
|
||||
url: "/resource/oss/download/1981738218223079425"
|
||||
}
|
||||
```
|
||||
|
||||
### 期望的数据格式
|
||||
|
||||
```javascript
|
||||
{
|
||||
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
|
||||
|
||||
---
|
||||
|
||||
## 调试信息
|
||||
|
||||
### 前端上传请求
|
||||
|
||||
```javascript
|
||||
// 调用上传接口
|
||||
POST /resource/oss/upload
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
// FormData:
|
||||
file: [Blob] photo.jpg
|
||||
bizType: "dorm_violation_attachment"
|
||||
```
|
||||
|
||||
### 后端返回(上传成功)
|
||||
|
||||
```javascript
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
ossId: "1981738218223079425",
|
||||
url: "/resource/oss/download/1981738218223079425",
|
||||
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139" // ⚠️ 缺少扩展名
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 后端返回(回显查询)
|
||||
|
||||
```javascript
|
||||
// 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的文件名应包含扩展名
|
||||
|
||||
```java
|
||||
@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类包含正确的字段值
|
||||
|
||||
```java
|
||||
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`
|
||||
|
||||
**需要确认的字段**:
|
||||
```sql
|
||||
-- 检查字段定义
|
||||
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` 中添加了兜底逻辑
|
||||
|
||||
```javascript
|
||||
// 检测 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
|
||||
**状态**: 🔴 待修复
|
||||
|
||||
Reference in new issue
Block a user