Softhub软件下载站实战开发(七):集成MinIO实现文件存储功能

发布于:2025-06-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

Softhub软件下载站实战开发(七):集成MinIO实现文件存储功能 🚀

本篇将详细介绍如何为Softhub软件下载站集成MinIO对象存储,实现软件文件的安全高效管理!

1. 引言

在软件下载站开发中,文件存储管理是核心功能之一。上一篇文章我们实现了软件配置面板,现在我们需要一个强大的存储解决方案来管理软件安装包。本文将展示如何集成MinIO对象存储到Softhub项目中!

为什么选择MinIO?

  • ✅ 高性能对象存储
  • ✅ 开源且兼容S3 API
  • ✅ 简单易用的管理界面
  • ✅ 支持分布式部署

2. MinIO配置详解

首先在 manifest/config/config.yaml 中添加MinIO配置:

minio:
  # MinIO服务器地址
  endpoint: "127.0.0.1:9000"
  # 访问密钥
  accessKey: "minioadmin"
  # 密钥
  secretKey: "12345678"
  # 存储桶名称
  bucket: "softhub"
  # 是否使用SSL
  useSSL: false
  # 基础路径
  basePath: "/"

3. MinIO客户端初始化

internal/utils/storage/minio_utils.go 中实现MinIO客户端初始化:

package storage

import (
	"context"
	"io"
	"mime"
	"path/filepath"
	"strings"

	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/tiger1103/gfast/v3/internal/app/admin/common/config"
	"github.com/tiger1103/gfast/v3/internal/app/admin/common/global"
)

// MinioDrive minio对象存储驱动
type MinioDrive struct{}

// GetClient 获取MinIO客户端(单例模式)
func (d *MinioDrive) GetClient() (*minio.Client, error) {
	if global.Client != nil {
		return global.Client, nil
	}
	client, err := minio.New(config.MINIO_ENDPOINT, &minio.Options{
		Creds:  credentials.NewStaticV4(
			config.MINIO_ACCESS_KEY, 
			config.MINIO_SECRET_KEY, 
			""),
		Secure: config.MINIO_USE_SSL,
	})
	global.Client = client
	return global.Client, err
}

4. 文件上传实现

4.1 基础上传方法

// Upload 上传文件到MinIO
func (d *MinioDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, md5 string, err error) {
	client, err := d.GetClient()
	if err != nil {
		return "", "", err
	}
	
	// 计算文件MD5
	md5, _ = gmd5.Encrypt(file)
	ext := gfile.Ext(file.Filename)
	fileName := strings.ToLower(md5 + ext)
	
	// 按日期组织目录结构
	fullPath = config.MINIO_BASE_PATH + gtime.Date() + "/" + fileName

	reader, err := file.Open()
	if err != nil {
		return "", "", err
	}
	defer reader.Close()

	// 设置内容类型
	opts := minio.PutObjectOptions{
		ContentType: mime.TypeByExtension(filepath.Ext(file.Filename)),
	}
	if opts.ContentType == "" {
		opts.ContentType = "application/octet-stream"
	}

	// 执行上传
	_, err = client.PutObject(
		ctx, 
		config.MINIO_BUCKET, 
		fullPath, 
		reader, 
		file.Size, 
		opts)
		
	return fullPath, md5, err
}

4.2 指定路径上传

// UploadWithPath 按指定路径上传文件
func (d *MinioDrive) UploadWithPath(ctx context.Context, file *ghttp.UploadFile, savePath string) error {
	client, err := d.GetClient()
	if err != nil {
		return err
	}
	
	reader, err := file.Open()
	if err != nil {
		return err
	}
	
	opts := minio.PutObjectOptions{
		ContentType: mime.TypeByExtension(filepath.Ext(file.Filename)),
	}
	if opts.ContentType == "" {
		opts.ContentType = "application/octet-stream"
	}
	
	_, err = client.PutObject(
		ctx, 
		config.MINIO_BUCKET, 
		savePath, 
		reader, 
		file.Size, 
		opts)
	return err
}

5. 文件下载与删除

5.1 文件下载实现

// GetObject 获取MinIO中的文件内容
func (d *MinioDrive) GetObject(ctx context.Context, fullPath string) ([]byte, error) {
	client, err := d.GetClient()
	if err != nil {
		return nil, err
	}
	
	obj, err := client.GetObject(
		ctx, 
		config.MINIO_BUCKET, 
		fullPath, 
		minio.GetObjectOptions{})
	if err != nil {
		return nil, err
	}
	defer obj.Close()
	
	data, err := io.ReadAll(obj)
	if err != nil {
		return nil, err
	}
	return data, nil
}

5.2 文件删除实现

// Remove 删除MinIO中的文件
func (d *MinioDrive) Remove(ctx context.Context, fullPath string) error {
	client, err := d.GetClient()
	if err != nil {
		return err
	}
	
	err = client.RemoveObject(
		ctx, 
		config.MINIO_BUCKET, 
		fullPath, 
		minio.RemoveObjectOptions{})
	return err
}

6. 配置加载与初始化

internal/cmd/cmd.go 中添加配置加载逻辑:

func readConfig(ctx context.Context) {
	// 读取MinIO配置
	endpoint, _ := g.Cfg().Get(ctx, "minio.endpoint")
	accessKey, _ := g.Cfg().Get(ctx, "minio.accessKey")
	secretKey, _ := g.Cfg().Get(ctx, "minio.secretKey")
	bucket, _ := g.Cfg().Get(ctx, "minio.bucket")
	useSSL, _ := g.Cfg().Get(ctx, "minio.useSSL")
	basePath, _ := g.Cfg().Get(ctx, "minio.basePath")

	// 设置全局配置
	config.MINIO_ENDPOINT = endpoint.String()
	config.MINIO_ACCESS_KEY = accessKey.String()
	config.MINIO_SECRET_KEY = secretKey.String()
	config.MINIO_BUCKET = bucket.String()
	config.MINIO_USE_SSL = useSSL.Bool()
	config.MINIO_BASE_PATH = basePath.String()
	
	// 确保基础路径以/结尾
	if config.MINIO_BASE_PATH != "" && 
	   config.MINIO_BASE_PATH[len(config.MINIO_BASE_PATH)-1:] != "/" {
		config.MINIO_BASE_PATH += "/"
	}
}

8. 部署MinIO的Docker指南

详细minio部署方案参考docker部署MinIO对象存储实践:含控制台功能恢复方案

使用Docker快速部署MinIO:

# 创建MinIO容器
docker run -d \
  -p 9000:9000 \
  -p 9090:9090 \
  --name minio \
  -v /mnt/data:/data \
  -e "MINIO_ROOT_USER=minioadmin" \
  -e "MINIO_ROOT_PASSWORD=12345678" \
  minio/minio server /data --console-address ":9001"

访问管理界面:http://localhost:9001

image.png

创建softhub的bucket,用于存储软件相关数据

11. 总结

通过本文,我们完成了:

  1. MinIO集成 - 配置并初始化MinIO客户端
  2. 文件上传 - 实现文件上传到MinIO存储桶
  3. 文件管理 - 实现文件的下载和删除
  4. 部署指南 - Docker快速部署MinIO服务

MinIO的集成大大提升了Softhub的文件管理能力,为后续实现软件版本管理、下载统计等功能奠定了基础。


softhub系列往期文章

  1. Softhub软件下载站实战开发(一):项目总览
  2. Softhub软件下载站实战开发(二):项目基础框架搭建
  3. Softhub软件下载站实战开发(三):平台管理模块实战
  4. Softhub软件下载站实战开发(四):代码生成器设计与实现
  5. Softhub软件下载站实战开发(五):分类模块实现
  6. Softhub软件下载站实战开发(六):软件配置面板实现

网站公告

今日签到

点亮在社区的每一天
去签到