- 添加认证相关API文档(登录认证、验证码) - 添加权限管理API文档(菜单管理、角色管理) - 添加系统管理API文档(图片管理、文件管理、登录日志) - 添加用户管理API文档 - 完善项目API文档结构,提升开发体验
21 KiB
文件管理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 | 是 | 上传的文件 |
响应示例:
{
"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 | 上传时间 |
调用示例:
curl -X POST \
http://localhost:18099/coder/file/uploadFile/10/avatar/file \
-H "Authorization: Bearer your-token-value" \
-F "file=@avatar.jpg"
前端使用示例:
// 使用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}
接口描述: 匿名上传文件到服务器(无需登录认证)
是否需要认证: 否
权限要求: 无
路径参数: 同上传文件接口
请求参数: 同上传文件接口
响应示例: 同上传文件接口
调用示例:
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 |
响应示例:
{
"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"
}
调用示例:
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外)
响应示例:
{
"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"
}
调用示例:
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 |
响应示例:
{
"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"
}
调用示例:
curl -X GET \
http://localhost:18099/coder/sysFile/getById/1 \
-H "Authorization: Bearer your-token-value"
4. 新增文件记录
接口地址: POST /coder/sysFile/add
接口描述: 新增系统文件记录
是否需要认证: 是
权限要求: system:file:upload
请求参数:
{
"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字符 |
响应示例:
{
"status": 200,
"msg": "SUCCESS",
"data": "新增成功",
"traceId": "trace-123456"
}
调用示例:
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
请求参数:
{
"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 |
| 其他参数 | - | - | 同新增文件记录 | - |
响应示例:
{
"status": 200,
"msg": "SUCCESS",
"data": "修改成功",
"traceId": "trace-123456"
}
调用示例:
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 |
响应示例:
{
"status": 200,
"msg": "SUCCESS",
"data": "删除成功",
"traceId": "trace-123456"
}
调用示例:
curl -X POST \
http://localhost:18099/coder/sysFile/deleteById/1 \
-H "Authorization: Bearer your-token-value"
7. 批量删除文件
接口地址: POST /coder/sysFile/batchDelete
接口描述: 批量删除文件记录和物理文件
是否需要认证: 是
权限要求: system:file:remove
请求参数:
{
"ids": [1, 2, 3]
}
请求参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ids | Long[] | 是 | 文件ID数组 |
响应示例:
{
"status": 200,
"msg": "SUCCESS",
"data": "删除成功",
"traceId": "trace-123456"
}
调用示例:
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. 文件存储配置
# 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. 文件夹分类
// 文件夹类型枚举
public enum FolderType {
AVATAR("avatar", "用户头像"),
DOCUMENT("document", "文档文件"),
IMAGE("image", "图片文件"),
TEMP("temp", "临时文件"),
EXPORT("export", "导出文件");
private final String code;
private final String name;
}
3. 文件上传工具类
@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. 监控告警
- 存储监控: 监控存储空间使用
- 性能监控: 监控上传下载性能
- 安全监控: 监控异常文件操作
- 容量告警: 存储空间不足告警
注意事项
- 文件安全: 严格验证上传文件类型和内容
- 存储路径: 确保文件存储路径安全
- 权限控制: 合理设置文件访问权限
- 磁盘空间: 定期清理无效文件,避免磁盘满
- 备份策略: 重要文件需要备份
- 访问控制: 防止文件被恶意访问
- 性能考虑: 大文件上传时注意性能影响
- 并发控制: 处理并发上传时的文件冲突
- 错误处理: 完善的错误处理和回滚机制
- 日志审计: 记录所有文件操作日志