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

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软件下载站实战开发(六):软件配置面板实现
资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 在 Android 应用开发中,开发一款仿 OPPO 手机计算器的应用是极具实践价值的任务,它融合了 UI 设计、事件处理以及数学逻辑等多方面的技术要点。当前的“最新版仿 OPPO 手机计算器--android.rar”压缩包中,提供了该计算器应用的源代码,这为开发者深入学习 Android 编程提供了宝贵的资源。 UI 设计是构建此类计算器应用的基石。OPPO 手机的计算器界面以清晰的布局和良好的用户交互体验著称,其中包括数字键、运算符键以及用于显示结果的区域等关键元素。开发者需借助 Android Studio 中的 XML 布局文件来定义这些界面元素,可选用 LinearLayout、GridLayout 或 ConstraintLayout 等布局管理器,并搭配 Button 控件来实现各个按键功能。同时,还需考虑不同分辨率屏幕和设备尺寸的适配问题,这通常涉及 Density Independent Pixel(dp)单位的应用以及 Android 尺寸资源的合理配置。 事件处理构成了计算器的核心功能开发者要在每个按钮的点击事件中编写相应的处理代码,通常通过实现 OnClickListener 接口来完成。例如,当用户点击数字键时,相应的值会被添加到显示区域;点击运算符键时,则会保存当前操作数并设定运算类型。而对于等号(=)按钮,需要执行计算操作,这往往需要借助栈数据结构来存储操作数和运算符,并运用算法解析表达式以完成计算。 数学逻辑的实现则是计算器功能的关键体现。在 Android 应用中,开发者可以利用 Java 内置的 Math 类,或者自行设计算法来完成计算任务。基本的加减乘除运算可通过简单的算术操作实现,而像求幂、开方等复杂运算则需调用 Math 类的相关方法。此外
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值