package upload import ( "bytes" "context" "errors" "io" "mime/multipart" "path/filepath" "strings" "sundynix-go/global" "sundynix-go/utils" "time" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "go.uber.org/zap" ) var MinioClient *Minio // 优化性能,但是不支持动态配置 type Minio struct { Client *minio.Client bucket string } func GetMinio(endpoint, accessKey, secretKey, bucketName string, useSSL bool) (*Minio, error) { if MinioClient != nil { return MinioClient, nil } // Initialize minio client object. minioClient, err := minio.New(endpoint, &minio.Options{ Creds: credentials.NewStaticV4(accessKey, secretKey, ""), Secure: useSSL, // Set to true if using https }) if err != nil { return nil, err } // 创建bucket err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{}) if err != nil { // 判断是否已经存在 exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName) if errBucketExists == nil && exists { global.Logger.Info("Bucket already exists") } else { return nil, err } } MinioClient = &Minio{ Client: minioClient, bucket: bucketName, } return MinioClient, nil } func (m *Minio) UploadFile(file *multipart.FileHeader) (filePathres, key string, uploadErr error) { f, openErr := file.Open() // mutipart.File to os.File if openErr != nil { global.Logger.Error("function file.Open() Failed", zap.Any("err", openErr.Error())) return "", "", errors.New("function file.Open() Failed, err:" + openErr.Error()) } buffer := bytes.Buffer{} _, err := io.Copy(&buffer, f) if err != nil { global.Logger.Error("读取文件失败", zap.Any("err", err.Error())) return "", "", errors.New("读取文件失败, err:" + err.Error()) } f.Close() // 创建文件 defer 关闭 //对文件名进行加密存储 ext := filepath.Ext(file.Filename) filename := utils.MD5V([]byte(strings.TrimSuffix(file.Filename, ext))) + ext if global.Config.Minio.BasePath == "" { filePathres = "uploads/" + time.Now().Format("2006-01-02") + "/" + filename // uploads/2025-09-17/xxxx.png } else { filePathres = global.Config.Minio.BasePath + "/" + time.Now().Format("2006-01-02") + "/" + filename } // 设置超时10分钟 ctx, cancel := context.WithTimeout(context.Background(), time.Minute*10) defer cancel() //大文件自动切换为分片上传 info, err := m.Client.PutObject(ctx, global.Config.Minio.BucketName, filePathres, &buffer, file.Size, minio.PutObjectOptions{ ContentType: "application/octet-stream", }) if err != nil { global.Logger.Error("上传文件到minio失败", zap.Any("err", err.Error())) return "", "", errors.New("上传文件到minio失败, err:" + err.Error()) } //http://127.0.0.1:9000/planting-fun/uploads/2025-09-17/211476f3837fc7acbaebf0f901c1bd68.png return global.Config.Minio.BucketUrl + "/" + info.Key, filePathres, nil } func (m *Minio) DeleteFile(key string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() err := m.Client.RemoveObject(ctx, m.bucket, key, minio.RemoveObjectOptions{}) return err }