| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package services
- import (
- "context"
- "fmt"
- "io"
- "time"
- "github.com/minio/minio-go/v7"
- "github.com/minio/minio-go/v7/pkg/credentials"
- )
- // MinioService 结构体,持有Minio客户端和配置
- type MinioService struct {
- client *minio.Client
- endpoint string
- }
- // NewMinioService 构造函数,用于初始化MinioService
- func NewMinioService(endpoint, accessKeyID, secretAccessKey string, useSSL bool) *MinioService {
- // 初始化minio client对象[citation:2]
- client, err := minio.New(endpoint, &minio.Options{
- Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
- Secure: useSSL,
- })
- if err != nil {
- fmt.Printf("failed to create MinIO client: %w", err)
- return nil
- }
- return &MinioService{
- client: client,
- endpoint: endpoint,
- }
- }
- // BucketExists 检查存储桶是否存在[citation:2]
- func (s *MinioService) BucketExists(bucketName string) (bool, error) {
- exists, err := s.client.BucketExists(context.Background(), bucketName)
- if err != nil {
- return false, fmt.Errorf("failed to check if bucket '%s' exists: %w", bucketName, err)
- }
- return exists, nil
- }
- // MakeBucket 创建存储桶(如果不存在)[citation:2]
- func (s *MinioService) MakeBucket(bucketName string) error {
- exists, err := s.BucketExists(bucketName)
- if err != nil {
- return err
- }
- if !exists {
- // 创建一个存储桶[citation:2]
- err = s.client.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{})
- if err != nil {
- return fmt.Errorf("failed to create bucket '%s': %w", bucketName, err)
- }
- }
- return nil
- }
- // UploadFile 上传文件(使用默认日期目录)
- func (s *MinioService) UploadFile(bucketName string, reader io.Reader, objectName string) (string, error) {
- // 使用当前日期生成目录,格式 yyyy-MM-dd
- dir := time.Now().Format("2006-01-02")
- return s.uploadFileToDir(bucketName, reader, objectName, dir)
- }
- // UploadFileToDir 上传文件到指定目录
- func (s *MinioService) UploadFileToDir(bucketName string, reader io.Reader, objectName, dir string) (string, error) {
- return s.uploadFileToDir(bucketName, reader, objectName, dir)
- }
- // uploadFileToDir 内部上传方法
- func (s *MinioService) uploadFileToDir(bucketName string, reader io.Reader, objectName, dir string) (string, error) {
- // 确保存储桶存在
- if err := s.MakeBucket(bucketName); err != nil {
- return "", err
- }
- // 构建对象路径
- objectPath := fmt.Sprintf("%s/%s", dir, objectName)
- // 上传对象。PutObject内部已支持分块上传[citation:7],partSize参数(10MiB)与你的Java代码对应。
- uploadInfo, err := s.client.PutObject(context.Background(), bucketName, objectPath, reader, -1, minio.PutObjectOptions{
- ContentType: "application/octet-stream",
- PartSize: 10 * 1024 * 1024, // 10 MiB
- })
- if err != nil {
- return "", fmt.Errorf("failed to upload file '%s' to bucket '%s': %w", objectPath, bucketName, err)
- }
- // 返回路径,这里返回对象在桶内的完整键(Key),你也可以选择返回一个可访问的URL
- // 格式类似于Java版本返回的 "/bucket/dir/objectName"
- return fmt.Sprintf("/%s/%s", bucketName, uploadInfo.Key), nil
- }
- // GetFileURL 获取文件的预签名URL(用于临时访问)
- func (s *MinioService) GetFileURL(bucketName, objectName string, expiry time.Duration) (string, error) {
- // 生成一个 presigned GET URL,默认7天有效[citation:2]
- if expiry == 0 {
- expiry = 7 * 24 * time.Hour
- }
- url, err := s.client.PresignedGetObject(context.Background(), bucketName, objectName, expiry, nil)
- if err != nil {
- return "", fmt.Errorf("failed to generate URL for '%s/%s': %w", bucketName, objectName, err)
- }
- return url.String(), nil
- }
- // DownloadFile 下载文件,返回一个读取流[citation:8]
- func (s *MinioService) DownloadFile(bucketName, objectName string) (*minio.Object, error) {
- reader, err := s.client.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
- if err != nil {
- return nil, fmt.Errorf("failed to download file '%s' from bucket '%s': %w", objectName, bucketName, err)
- }
- // 注意:调用者需要负责关闭这个 reader (defer reader.Close())
- return reader, nil
- }
- // RemoveFile 删除文件
- func (s *MinioService) RemoveFile(bucketName, objectName string) error {
- err := s.client.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
- if err != nil {
- return fmt.Errorf("failed to remove file '%s' from bucket '%s': %w", objectName, bucketName, err)
- }
- return nil
- }
- // IsObjectExist 检查对象是否存在
- func (s *MinioService) IsObjectExist(bucketName, objectName string) (bool, error) {
- _, err := s.client.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
- if err != nil {
- // 尝试将错误转换为MinIO的错误响应
- errResp := minio.ToErrorResponse(err)
- if errResp.Code == "NoSuchKey" {
- return false, nil
- }
- return false, fmt.Errorf("failed to stat object '%s' in bucket '%s': %w", objectName, bucketName, err)
- }
- return true, nil
- }
|