# 文件管理API ## 概述 文件管理模块提供文件上传、下载、存储管理等功能。支持多种文件类型,提供文件记录管理和批量操作功能。分为通用文件上传接口和系统文件记录管理两部分。 ## 权限说明 文件管理接口需要相应的权限才能访问: | 操作 | 权限码 | 说明 | |------|--------|------| | 查询文件列表 | `system:file:list` | 查看文件列表权限 | | 上传文件 | `system:file:upload` | 上传文件权限 | | 下载文件 | `system:file:download` | 下载文件权限 | | 删除文件 | `system:file:remove` | 删除文件权限 | ## 文件上传接口 ### 1. 上传文件(需认证) **接口地址**: `POST /coder/file/uploadFile/{fileSize}/{folderName}/{fileParam}` **接口描述**: 上传文件到服务器(需要登录认证) **是否需要认证**: 是 **权限要求**: `system:file:upload` **请求头**: ``` Authorization: Bearer your-token-value Content-Type: multipart/form-data ``` **路径参数**: | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | fileSize | Integer | 是 | 文件大小限制(MB) | 10 | | folderName | String | 是 | 存储文件夹名称 | avatar | | fileParam | String | 是 | 文件参数名 | file | **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | file | File | 是 | 上传的文件 | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": { "fileName": "avatar.jpg", "originalName": "my-avatar.jpg", "filePath": "/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "fileUrl": "http://localhost:18099/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "fileSize": 1024000, "fileType": "jpg", "uploadTime": "2024-07-05 10:00:00" }, "traceId": "trace-123456" } ``` **响应参数说明**: | 参数名 | 类型 | 说明 | |--------|------|------| | fileName | String | 存储文件名 | | originalName | String | 原始文件名 | | filePath | String | 文件相对路径 | | fileUrl | String | 文件访问URL | | fileSize | Long | 文件大小(字节) | | fileType | String | 文件类型 | | uploadTime | String | 上传时间 | **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/file/uploadFile/10/avatar/file \ -H "Authorization: Bearer your-token-value" \ -F "file=@avatar.jpg" ``` **前端使用示例**: ```javascript // 使用FormData上传文件 function uploadFile(file, folder, maxSize) { const formData = new FormData(); formData.append('file', file); fetch(`/coder/file/uploadFile/${maxSize}/${folder}/file`, { method: 'POST', headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }, body: formData }) .then(response => response.json()) .then(data => { if (data.status === 200) { console.log('上传成功:', data.data.fileUrl); } else { console.error('上传失败:', data.msg); } }); } ``` --- ### 2. 匿名上传文件 **接口地址**: `POST /coder/file/uploadAnyFile/{fileSize}/{folderName}/{fileParam}` **接口描述**: 匿名上传文件到服务器(无需登录认证) **是否需要认证**: 否 **权限要求**: 无 **路径参数**: 同上传文件接口 **请求参数**: 同上传文件接口 **响应示例**: 同上传文件接口 **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/file/uploadAnyFile/5/temp/file \ -F "file=@document.pdf" ``` **使用场景**: - 用户注册时上传头像 - 访客上传临时文件 - 公开资源上传 --- ## 系统文件记录管理接口 ### 1. 分页查询文件列表 **接口地址**: `GET /coder/sysFile/listPage` **接口描述**: 分页查询系统文件记录列表 **是否需要认证**: 是 **权限要求**: `system:file:list` **请求头**: ``` Authorization: Bearer your-token-value ``` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | pageNo | Integer | 否 | 页码 | 1 | | pageSize | Integer | 否 | 每页大小 | 10 | | fileName | String | 否 | 文件名称 | avatar.jpg | | fileType | String | 否 | 文件类型 | jpg | | folderName | String | 否 | 文件夹名称 | avatar | | beginTime | String | 否 | 开始时间 | 2024-01-01 | | endTime | String | 否 | 结束时间 | 2024-12-31 | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": { "records": [ { "fileId": 1, "fileName": "avatar_20240705_001.jpg", "originalName": "my-avatar.jpg", "filePath": "/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "fileUrl": "http://localhost:18099/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "folderName": "avatar", "fileSize": 1024000, "fileType": "jpg", "contentType": "image/jpeg", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "用户头像", "createBy": "admin", "createTime": "2024-07-05 10:00:00", "updateBy": "admin", "updateTime": "2024-07-05 10:00:00" } ], "total": 1, "size": 10, "current": 1, "pages": 1 }, "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X GET \ "http://localhost:18099/coder/sysFile/listPage?pageNo=1&pageSize=10&fileName=avatar" \ -H "Authorization: Bearer your-token-value" ``` --- ### 2. 查询所有文件 **接口地址**: `GET /coder/sysFile/list` **接口描述**: 查询所有系统文件记录(不分页) **是否需要认证**: 是 **权限要求**: `system:file:list` **请求参数**: 同分页查询(除pageNo、pageSize外) **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": [ { "fileId": 1, "fileName": "avatar_20240705_001.jpg", "originalName": "my-avatar.jpg", "filePath": "/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "fileUrl": "http://localhost:18099/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "folderName": "avatar", "fileSize": 1024000, "fileType": "jpg", "contentType": "image/jpeg", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "用户头像", "createBy": "admin", "createTime": "2024-07-05 10:00:00", "updateBy": "admin", "updateTime": "2024-07-05 10:00:00" } ], "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X GET \ "http://localhost:18099/coder/sysFile/list?fileType=jpg" \ -H "Authorization: Bearer your-token-value" ``` --- ### 3. 根据ID查询文件 **接口地址**: `GET /coder/sysFile/getById/{id}` **接口描述**: 根据文件ID查询文件详细信息 **是否需要认证**: 是 **权限要求**: `system:file:list` **路径参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 文件ID | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": { "fileId": 1, "fileName": "avatar_20240705_001.jpg", "originalName": "my-avatar.jpg", "filePath": "/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "fileUrl": "http://localhost:18099/upload/avatar/2024/07/05/avatar_20240705_001.jpg", "folderName": "avatar", "fileSize": 1024000, "fileType": "jpg", "contentType": "image/jpeg", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "用户头像", "createBy": "admin", "createTime": "2024-07-05 10:00:00", "updateBy": "admin", "updateTime": "2024-07-05 10:00:00" }, "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X GET \ http://localhost:18099/coder/sysFile/getById/1 \ -H "Authorization: Bearer your-token-value" ``` --- ### 4. 新增文件记录 **接口地址**: `POST /coder/sysFile/add` **接口描述**: 新增系统文件记录 **是否需要认证**: 是 **权限要求**: `system:file:upload` **请求参数**: ```json { "fileName": "document_20240705_001.pdf", "originalName": "重要文档.pdf", "filePath": "/upload/documents/2024/07/05/document_20240705_001.pdf", "fileUrl": "http://localhost:18099/upload/documents/2024/07/05/document_20240705_001.pdf", "folderName": "documents", "fileSize": 2048000, "fileType": "pdf", "contentType": "application/pdf", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "重要文档" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | 校验规则 | |--------|------|------|------|----------| | fileName | String | 是 | 存储文件名 | 不能为空 | | originalName | String | 是 | 原始文件名 | 不能为空 | | filePath | String | 是 | 文件相对路径 | 不能为空 | | fileUrl | String | 是 | 文件访问URL | 不能为空 | | folderName | String | 是 | 文件夹名称 | 不能为空 | | fileSize | Long | 是 | 文件大小 | 必须大于0 | | fileType | String | 是 | 文件类型 | 不能为空 | | contentType | String | 是 | MIME类型 | 不能为空 | | fileStatus | String | 是 | 文件状态 | 0-正常 1-删除 | | uploadUserId | Long | 否 | 上传用户ID | 有效的用户ID | | uploadUserName | String | 否 | 上传用户名 | 可为空 | | remark | String | 否 | 备注信息 | 最长200字符 | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": "新增成功", "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/sysFile/add \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-token-value" \ -d '{ "fileName": "document_20240705_001.pdf", "originalName": "重要文档.pdf", "filePath": "/upload/documents/2024/07/05/document_20240705_001.pdf", "fileUrl": "http://localhost:18099/upload/documents/2024/07/05/document_20240705_001.pdf", "folderName": "documents", "fileSize": 2048000, "fileType": "pdf", "contentType": "application/pdf", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "重要文档" }' ``` --- ### 5. 修改文件信息 **接口地址**: `POST /coder/sysFile/update` **接口描述**: 修改系统文件记录信息 **是否需要认证**: 是 **权限要求**: `system:file:edit` **请求参数**: ```json { "fileId": 1, "fileName": "document_20240705_001.pdf", "originalName": "重要文档.pdf", "filePath": "/upload/documents/2024/07/05/document_20240705_001.pdf", "fileUrl": "http://localhost:18099/upload/documents/2024/07/05/document_20240705_001.pdf", "folderName": "documents", "fileSize": 2048000, "fileType": "pdf", "contentType": "application/pdf", "fileStatus": "0", "uploadUserId": 1, "uploadUserName": "admin", "remark": "重要文档(已更新)" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | 校验规则 | |--------|------|------|------|----------| | fileId | Long | 是 | 文件ID | 必须是有效的文件ID | | 其他参数 | - | - | 同新增文件记录 | - | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": "修改成功", "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/sysFile/update \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-token-value" \ -d '{ "fileId": 1, "fileName": "document_20240705_001.pdf", "originalName": "重要文档.pdf", "remark": "重要文档(已更新)" }' ``` --- ### 6. 删除文件 **接口地址**: `POST /coder/sysFile/deleteById/{id}` **接口描述**: 根据ID删除文件记录和物理文件 **是否需要认证**: 是 **权限要求**: `system:file:remove` **路径参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 文件ID | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": "删除成功", "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/sysFile/deleteById/1 \ -H "Authorization: Bearer your-token-value" ``` --- ### 7. 批量删除文件 **接口地址**: `POST /coder/sysFile/batchDelete` **接口描述**: 批量删除文件记录和物理文件 **是否需要认证**: 是 **权限要求**: `system:file:remove` **请求参数**: ```json { "ids": [1, 2, 3] } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 文件ID数组 | **响应示例**: ```json { "status": 200, "msg": "SUCCESS", "data": "删除成功", "traceId": "trace-123456" } ``` **调用示例**: ```bash curl -X POST \ http://localhost:18099/coder/sysFile/batchDelete \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-token-value" \ -d '{ "ids": [1, 2, 3] }' ``` --- ## 文件字段说明 ### 基础字段 | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | fileId | Long | 文件ID | 1 | | fileName | String | 存储文件名 | avatar_20240705_001.jpg | | originalName | String | 原始文件名 | my-avatar.jpg | | filePath | String | 文件相对路径 | /upload/avatar/2024/07/05/avatar_20240705_001.jpg | | fileUrl | String | 文件访问URL | http://localhost:18099/upload/avatar/2024/07/05/avatar_20240705_001.jpg | ### 分类字段 | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | folderName | String | 文件夹名称 | avatar | | fileType | String | 文件扩展名 | jpg | | contentType | String | MIME类型 | image/jpeg | | fileSize | Long | 文件大小(字节) | 1024000 | ### 状态字段 | 字段名 | 类型 | 说明 | 示例 | |--------|------|------|------| | fileStatus | String | 文件状态 | 0-正常 1-删除 | | uploadUserId | Long | 上传用户ID | 1 | | uploadUserName | String | 上传用户名 | admin | | remark | String | 备注信息 | 用户头像 | --- ## 数据字典 ### 文件状态 (fileStatus) | 值 | 说明 | |----|------| | 0 | 正常 | | 1 | 已删除 | ### 常见文件类型 | 文件类型 | 扩展名 | MIME类型 | 说明 | |----------|--------|----------|------| | 图片 | jpg, jpeg, png, gif, bmp | image/* | 图片文件 | | 文档 | pdf, doc, docx, xls, xlsx, ppt, pptx | application/* | 办公文档 | | 音频 | mp3, wav, flac, aac | audio/* | 音频文件 | | 视频 | mp4, avi, mov, wmv | video/* | 视频文件 | | 压缩包 | zip, rar, 7z, tar, gz | application/* | 压缩文件 | | 文本 | txt, md, csv | text/* | 文本文件 | --- ## 文件配置 ### 1. 文件存储配置 ```yaml # application-dev.yml coder: # 文件存储路径 filePath: /data/upload/ # 文件访问域名 domain: http://localhost:18099 # 文件大小限制(MB) maxFileSize: 100 # 允许的文件类型 allowedTypes: - jpg - jpeg - png - gif - pdf - doc - docx - xls - xlsx # 禁止的文件类型 forbiddenTypes: - exe - bat - sh - jsp - php ``` ### 2. 文件夹分类 ```java // 文件夹类型枚举 public enum FolderType { AVATAR("avatar", "用户头像"), DOCUMENT("document", "文档文件"), IMAGE("image", "图片文件"), TEMP("temp", "临时文件"), EXPORT("export", "导出文件"); private final String code; private final String name; } ``` ### 3. 文件上传工具类 ```java @Component public class FileUploadUtil { /** * 上传文件 */ public FileUploadResult uploadFile(MultipartFile file, String folder, int maxSize) { // 1. 文件校验 validateFile(file, maxSize); // 2. 生成文件名 String fileName = generateFileName(file.getOriginalFilename()); // 3. 创建目录 String datePath = DateUtil.format(new Date(), "yyyy/MM/dd"); String dirPath = filePath + folder + "/" + datePath + "/"; FileUtil.createDirs(dirPath); // 4. 保存文件 String filePath = dirPath + fileName; file.transferTo(new File(filePath)); // 5. 生成访问URL String fileUrl = domain + "/upload/" + folder + "/" + datePath + "/" + fileName; // 6. 返回结果 return FileUploadResult.builder() .fileName(fileName) .originalName(file.getOriginalFilename()) .filePath(filePath) .fileUrl(fileUrl) .fileSize(file.getSize()) .fileType(FileUtil.getExtension(fileName)) .uploadTime(new Date()) .build(); } /** * 文件校验 */ private void validateFile(MultipartFile file, int maxSize) { if (file.isEmpty()) { throw new BusinessException("文件不能为空"); } if (file.getSize() > maxSize * 1024 * 1024) { throw new BusinessException("文件大小不能超过" + maxSize + "MB"); } String extension = FileUtil.getExtension(file.getOriginalFilename()); if (!allowedTypes.contains(extension.toLowerCase())) { throw new BusinessException("不支持的文件类型:" + extension); } if (forbiddenTypes.contains(extension.toLowerCase())) { throw new BusinessException("禁止上传的文件类型:" + extension); } } /** * 生成文件名 */ private String generateFileName(String originalName) { String extension = FileUtil.getExtension(originalName); String baseName = FileUtil.getBaseName(originalName); String timestamp = DateUtil.format(new Date(), "yyyyMMdd_HHmmss"); String random = RandomUtil.randomString(3); return baseName + "_" + timestamp + "_" + random + "." + extension; } } ``` --- ## 错误码说明 | 错误码 | 错误信息 | 说明 | |--------|----------|------| | 400 | 文件不能为空 | 上传文件为空 | | 400 | 文件大小不能超过{size}MB | 文件大小超过限制 | | 400 | 不支持的文件类型 | 文件类型不在允许列表中 | | 400 | 禁止上传的文件类型 | 文件类型在禁止列表中 | | 400 | 文件名不能为空 | 文件名为空 | | 400 | 文件路径不能为空 | 文件路径为空 | | 400 | 文件不存在 | 文件ID不存在 | | 400 | 文件已被删除 | 文件状态为已删除 | | 401 | 当前会话未登录 | 未登录或Token无效 | | 403 | 权限不足 | 没有相应的操作权限 | | 500 | 文件上传失败 | 文件保存到磁盘失败 | | 500 | 文件删除失败 | 物理文件删除失败 | | 500 | 磁盘空间不足 | 服务器磁盘空间不足 | --- ## 安全特性 ### 1. 文件类型验证 - **扩展名校验**: 验证文件扩展名 - **MIME类型校验**: 验证文件MIME类型 - **文件内容校验**: 验证文件真实类型 - **黑名单过滤**: 禁止上传危险文件类型 ### 2. 文件大小限制 - **单文件大小限制**: 限制单个文件大小 - **总文件大小限制**: 限制用户总文件大小 - **磁盘空间检查**: 检查服务器磁盘空间 ### 3. 访问控制 - **权限验证**: 验证用户上传和访问权限 - **路径防护**: 防止路径遍历攻击 - **防盗链**: 防止文件被盗链 ### 4. 病毒扫描 - **文件扫描**: 上传文件病毒扫描 - **隔离机制**: 可疑文件隔离处理 - **定期扫描**: 定期扫描存储文件 --- ## 性能优化 ### 1. 文件存储 - **分目录存储**: 按日期和类型分目录存储 - **CDN加速**: 使用CDN加速文件访问 - **压缩存储**: 自动压缩图片文件 - **缓存策略**: 设置合适的缓存策略 ### 2. 上传优化 - **分片上传**: 大文件分片上传 - **断点续传**: 支持断点续传功能 - **并发上传**: 支持多文件并发上传 - **进度显示**: 实时显示上传进度 ### 3. 存储优化 - **重复文件检测**: 检测并避免重复文件 - **文件压缩**: 自动压缩文件 - **定期清理**: 清理临时文件和无效文件 - **存储监控**: 监控存储空间使用情况 --- ## 使用建议 ### 1. 文件命名规范 - **唯一性**: 确保文件名唯一 - **时间戳**: 包含时间戳信息 - **随机性**: 添加随机字符 - **可读性**: 保持一定的可读性 ### 2. 文件分类管理 - **按类型分类**: 不同类型文件存储在不同目录 - **按用户分类**: 不同用户文件分开存储 - **按时间分类**: 按年月日创建目录结构 - **按业务分类**: 按业务模块分类存储 ### 3. 安全防护 - **输入验证**: 严格验证上传文件 - **权限控制**: 细粒度的权限控制 - **日志记录**: 记录所有文件操作 - **备份策略**: 重要文件定期备份 ### 4. 监控告警 - **存储监控**: 监控存储空间使用 - **性能监控**: 监控上传下载性能 - **安全监控**: 监控异常文件操作 - **容量告警**: 存储空间不足告警 --- ## 注意事项 1. **文件安全**: 严格验证上传文件类型和内容 2. **存储路径**: 确保文件存储路径安全 3. **权限控制**: 合理设置文件访问权限 4. **磁盘空间**: 定期清理无效文件,避免磁盘满 5. **备份策略**: 重要文件需要备份 6. **访问控制**: 防止文件被恶意访问 7. **性能考虑**: 大文件上传时注意性能影响 8. **并发控制**: 处理并发上传时的文件冲突 9. **错误处理**: 完善的错误处理和回滚机制 10. **日志审计**: 记录所有文件操作日志