/** * MinIO 工具函数使用示例 * 这个文件展示了如何使用 minio.ts 中的各种函数 */ import { uploadFile, getFileUrl, deleteFile, listFiles, generateUniqueFileName, validateFileType, validateFileSize, downloadFile, fileExists, getFileInfo, } from './minio'; // ======================================== // 1. 上传文件示例 // ======================================== /** * 上传用户头像 */ async function uploadAvatar(file: File, userId: string) { // 验证文件类型 const allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if (!validateFileType(file.name, allowedTypes)) { throw new Error('不支持的图片格式'); } // 验证文件大小(5MB) const maxSize = 5 * 1024 * 1024; if (!validateFileSize(file.size, maxSize)) { throw new Error('文件大小超过限制(最大5MB)'); } // 生成唯一文件名,存储在 avatars 目录下 const path = generateUniqueFileName(file.name, `avatars/${userId}`); // 上传文件 const url = await uploadFile(file, path, { 'Content-Type': file.type, 'User-Id': userId, }); return { url, path }; } /** * 上传文章封面图 */ async function uploadPostCover(file: File, postId: string) { const allowedTypes = ['jpg', 'jpeg', 'png', 'webp']; if (!validateFileType(file.name, allowedTypes)) { throw new Error('不支持的图片格式'); } const maxSize = 10 * 1024 * 1024; // 10MB if (!validateFileSize(file.size, maxSize)) { throw new Error('文件大小超过限制(最大10MB)'); } // 按日期组织文件 const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const path = generateUniqueFileName( file.name, `posts/${year}/${month}/covers` ); const url = await uploadFile(file, path); return { url, path }; } /** * 上传文章内容中的图片 */ async function uploadPostImage(file: File, postId: string) { const allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if (!validateFileType(file.name, allowedTypes)) { throw new Error('不支持的图片格式'); } const maxSize = 5 * 1024 * 1024; // 5MB if (!validateFileSize(file.size, maxSize)) { throw new Error('文件大小超过限制(最大5MB)'); } const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const path = generateUniqueFileName( file.name, `posts/${year}/${month}/images` ); const url = await uploadFile(file, path); return { url, path }; } // ======================================== // 2. 获取文件URL示例 // ======================================== /** * 获取文件的公共访问URL */ function getPublicFileUrl(path: string) { return getFileUrl(path); } // ======================================== // 3. 删除文件示例 // ======================================== /** * 删除用户头像(更换头像时) */ async function deleteAvatar(avatarPath: string) { try { await deleteFile(avatarPath); console.log('头像删除成功'); } catch (error) { console.error('删除头像失败:', error); throw error; } } /** * 删除文章时,删除相关的所有图片 */ async function deletePostImages(postId: string) { try { // 列出文章相关的所有图片 const files = await listFiles(`posts/`, true); // 过滤出该文章的图片(根据实际情况调整逻辑) const postFiles = files.filter(file => file.name?.includes(postId) ); // 批量删除 const paths = postFiles.map(f => f.name).filter((name): name is string => !!name); if (paths.length > 0) { const { deleteFiles } = await import('./minio'); await deleteFiles(paths); console.log(`删除了 ${paths.length} 个文件`); } } catch (error) { console.error('删除文章图片失败:', error); throw error; } } // ======================================== // 4. 列出文件示例 // ======================================== /** * 获取用户的所有头像历史 */ async function getUserAvatars(userId: string) { try { const files = await listFiles(`avatars/${userId}/`, false); return files.map(file => ({ name: file.name, size: file.size, lastModified: file.lastModified, url: file.name ? getFileUrl(file.name) : null, })); } catch (error) { console.error('获取用户头像列表失败:', error); throw error; } } /** * 获取某月的所有文章封面 */ async function getPostCoversByMonth(year: number, month: number) { try { const monthStr = String(month).padStart(2, '0'); const files = await listFiles(`posts/${year}/${monthStr}/covers/`, false); return files.map(file => ({ name: file.name, size: file.size, url: file.name ? getFileUrl(file.name) : null, })); } catch (error) { console.error('获取封面列表失败:', error); throw error; } } // ======================================== // 5. 检查文件是否存在 // ======================================== /** * 检查头像是否存在 */ async function checkAvatarExists(avatarPath: string): Promise { return await fileExists(avatarPath); } // ======================================== // 6. 获取文件信息 // ======================================== /** * 获取文件详细信息 */ async function getFileDetails(path: string) { try { const info = await getFileInfo(path); return { size: info.size, lastModified: info.lastModified, etag: info.etag, contentType: info.metaData?.['content-type'], }; } catch (error) { console.error('获取文件信息失败:', error); throw error; } } // ======================================== // 7. 下载文件示例 // ======================================== /** * 下载文件到本地 */ async function downloadFileToBuffer(path: string): Promise { try { return await downloadFile(path); } catch (error) { console.error('下载文件失败:', error); throw error; } } // ======================================== // 8. 在 API Route 中使用示例 // ======================================== /** * Next.js API Route 示例:上传文件 * * 使用方法: * * // app/api/upload/route.ts * import { uploadFile, generateUniqueFileName } from '@/lib/minio'; * * export async function POST(request: Request) { * const formData = await request.formData(); * const file = formData.get('file') as File; * * if (!file) { * return Response.json({ error: '没有文件' }, { status: 400 }); * } * * const path = generateUniqueFileName(file.name, 'uploads'); * const url = await uploadFile(file, path); * * return Response.json({ url, path }); * } */ /** * Next.js API Route 示例:删除文件 * * // app/api/delete/route.ts * import { deleteFile } from '@/lib/minio'; * * export async function DELETE(request: Request) { * const { path } = await request.json(); * * if (!path) { * return Response.json({ error: '缺少文件路径' }, { status: 400 }); * } * * await deleteFile(path); * * return Response.json({ success: true }); * } */ // ======================================== // 导出示例函数 // ======================================== export { uploadAvatar, uploadPostCover, uploadPostImage, getPublicFileUrl, deleteAvatar, deletePostImages, getUserAvatars, getPostCoversByMonth, checkAvatarExists, getFileDetails, downloadFileToBuffer, };