204 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # 文件上传功能文档
 | ||
| 
 | ||
| ## 概述
 | ||
| 
 | ||
| 文件上传功能已完整实现,支持将文件保存到本地文件系统并记录到数据库中。
 | ||
| 
 | ||
| ## 功能特性
 | ||
| 
 | ||
| 1. **自动目录管理**:按年月日自动创建目录结构(如 `front/uploads/2024/01/15/`)
 | ||
| 2. **唯一文件名**:使用时间戳生成唯一文件名,避免重名冲突
 | ||
| 3. **文件类型识别**:自动识别文件类型(图片、文档、视频、音频、压缩包等)
 | ||
| 4. **数据库记录**:所有文件信息保存到 `yz_files` 表
 | ||
| 5. **用户关联**:自动关联当前登录用户
 | ||
| 6. **异常处理**:文件保存失败时自动清理已上传的文件
 | ||
| 
 | ||
| ## 文件结构
 | ||
| 
 | ||
| ```
 | ||
| front/
 | ||
| └── uploads/
 | ||
|     ├── 2024/
 | ||
|     │   ├── 01/
 | ||
|     │   │   ├── 15/
 | ||
|     │   │   │   ├── 20240115143045_example.jpg
 | ||
|     │   │   │   └── 20240115143046_document.pdf
 | ||
| ```
 | ||
| 
 | ||
| ## API 接口
 | ||
| 
 | ||
| ### 上传文件
 | ||
| 
 | ||
| **POST** `/api/files`
 | ||
| 
 | ||
| **请求头**:
 | ||
| ```
 | ||
| Authorization: Bearer <token>
 | ||
| Content-Type: multipart/form-data
 | ||
| ```
 | ||
| 
 | ||
| **请求参数**:
 | ||
| - `file` (File, required): 上传的文件
 | ||
| - `category` (String, optional): 文件分类,默认为"未分类"
 | ||
| - `tenant_id` (String, optional): 租户ID,默认为"default"
 | ||
| 
 | ||
| **响应示例**:
 | ||
| ```json
 | ||
| {
 | ||
|   "success": true,
 | ||
|   "message": "文件上传成功",
 | ||
|   "data": {
 | ||
|     "id": 1,
 | ||
|     "tenant_id": "default",
 | ||
|     "user_id": 123,
 | ||
|     "file_name": "example",
 | ||
|     "original_name": "example.jpg",
 | ||
|     "file_path": "uploads/2024/01/15/20240115143045_example.jpg",
 | ||
|     "file_url": "/uploads/2024/01/15/20240115143045_example.jpg",
 | ||
|     "file_size": 102400,
 | ||
|     "file_type": "image",
 | ||
|     "file_ext": ".jpg",
 | ||
|     "category": "未分类",
 | ||
|     "upload_by": "username",
 | ||
|     "upload_time": "2024-01-15T14:30:45Z"
 | ||
|   }
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| ## 后端实现
 | ||
| 
 | ||
| ### 路由配置
 | ||
| 
 | ||
| 在 `server/routers/router.go` 中配置:
 | ||
| 
 | ||
| ```go
 | ||
| // 文件管理路由
 | ||
| beego.Router("/api/files", &controllers.FileController{}, "get:GetAllFiles")
 | ||
| beego.Router("/api/files", &controllers.FileController{}, "post:Post")
 | ||
| beego.Router("/api/files/my", &controllers.FileController{}, "get:GetMyFiles")
 | ||
| beego.Router("/api/files/:id", &controllers.FileController{}, "get:GetFileById")
 | ||
| beego.Router("/api/files/:id", &controllers.FileController{}, "put:UpdateFile")
 | ||
| beego.Router("/api/files/:id", &controllers.FileController{}, "delete:DeleteFile")
 | ||
| ```
 | ||
| 
 | ||
| ### 控制器实现
 | ||
| 
 | ||
| `Post()` 方法位于 `server/controllers/file.go`:
 | ||
| 
 | ||
| 1. 验证用户登录状态
 | ||
| 2. 接收上传的文件
 | ||
| 3. 生成日期路径和唯一文件名
 | ||
| 4. 保存文件到本地
 | ||
| 5. 记录文件信息到数据库
 | ||
| 6. 返回文件信息
 | ||
| 
 | ||
| ## 前端使用
 | ||
| 
 | ||
| ### 基本用法
 | ||
| 
 | ||
| ```typescript
 | ||
| import { fileAPI } from '@/api/file'
 | ||
| 
 | ||
| // 创建 FormData
 | ||
| const formData = new FormData()
 | ||
| formData.append('file', fileObject) // fileObject 是 File 对象
 | ||
| formData.append('category', '文档')
 | ||
| formData.append('tenant_id', 'tenant-001')
 | ||
| 
 | ||
| // 上传文件
 | ||
| try {
 | ||
|   const response = await fileAPI.uploadFile(formData, {
 | ||
|     category: '文档',
 | ||
|     tenantId: 'tenant-001'
 | ||
|   })
 | ||
|   console.log('上传成功:', response.data)
 | ||
| } catch (error) {
 | ||
|   console.error('上传失败:', error)
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| ### Element Plus 上传组件
 | ||
| 
 | ||
| ```vue
 | ||
| <el-upload
 | ||
|   ref="uploadRef"
 | ||
|   drag
 | ||
|   :action="uploadUrl"
 | ||
|   :headers="uploadHeaders"
 | ||
|   :data="{ category: uploadForm.category }"
 | ||
|   :on-success="handleUploadSuccess"
 | ||
|   :on-error="handleUploadError"
 | ||
|   :before-upload="beforeUpload"
 | ||
|   multiple
 | ||
| >
 | ||
|   <el-icon><upload-filled /></el-icon>
 | ||
|   <div class="el-upload__text">
 | ||
|     将文件拖到此处,或<em>点击上传</em>
 | ||
|   </div>
 | ||
| </el-upload>
 | ||
| 
 | ||
| <script setup>
 | ||
| const uploadUrl = computed(() => {
 | ||
|   const baseUrl = import.meta.env.VITE_API_BASE_URL 
 | ||
|   return `${baseUrl}/api/files`
 | ||
| })
 | ||
| 
 | ||
| const uploadHeaders = computed(() => {
 | ||
|   const token = localStorage.getItem('token')
 | ||
|   return {
 | ||
|     'Authorization': `Bearer ${token}`
 | ||
|   }
 | ||
| })
 | ||
| 
 | ||
| const handleUploadSuccess = (response) => {
 | ||
|   console.log('上传成功:', response)
 | ||
| }
 | ||
| 
 | ||
| const beforeUpload = (file) => {
 | ||
|   const maxSize = 10 * 1024 * 1024 // 10MB
 | ||
|   if (file.size > maxSize) {
 | ||
|     ElMessage.error('文件大小不能超过 10MB!')
 | ||
|     return false
 | ||
|   }
 | ||
|   return true
 | ||
| }
 | ||
| </script>
 | ||
| ```
 | ||
| 
 | ||
| ## 文件访问
 | ||
| 
 | ||
| 上传后的文件可以通过以下URL访问:
 | ||
| 
 | ||
| ```
 | ||
| http://localhost:8080/uploads/2024/01/15/20240115143045_example.jpg
 | ||
| ```
 | ||
| 
 | ||
| 注意:需要配置 Beego 的静态文件服务来提供上传文件的访问。
 | ||
| 
 | ||
| 在 `server/conf/app.conf` 中添加:
 | ||
| 
 | ||
| ```conf
 | ||
| # 文件上传目录
 | ||
| StaticDir = /uploads:../front/uploads
 | ||
| ```
 | ||
| 
 | ||
| ## 安全注意事项
 | ||
| 
 | ||
| 1. **文件大小限制**:建议在前端和后端都添加文件大小限制
 | ||
| 2. **文件类型验证**:根据业务需求限制允许上传的文件类型
 | ||
| 3. **文件名安全**:避免用户控制文件名造成安全问题
 | ||
| 4. **权限控制**:确保只有授权用户可以上传文件
 | ||
| 5. **存储位置**:考虑使用对象存储服务(如 OSS、S3)替代本地存储
 | ||
| 
 | ||
| ## 数据库字段说明
 | ||
| 
 | ||
| `yz_files` 表的主要字段:
 | ||
| 
 | ||
| - `file_path`: 相对路径,用于存储和访问文件
 | ||
| - `file_url`: 访问URL
 | ||
| - `original_name`: 用户上传时的原始文件名
 | ||
| - `file_name`: 去除扩展名的文件名
 | ||
| - `file_type`: 文件类型(image, document, video, audio, archive, other)
 | ||
| - `category`: 用户自定义分类
 | ||
| 
 |