gin结合minio来做文件存储
一、使用docker
安装
-
1、安装
docker
sudo apt update sudo apt install -y docker.io sudo systemctl enable --now docker
-
2、配置自己的阿里云镜像,连接地址
-
3、拉取镜像
sudo docker pull minio/minio
-
4、创建容器
sudo docker run -d \-p 9000:9000 \-p 9001:9001 \-v /mnt/data:/data \-e "MINIO_ROOT_USER=admin" \-e "MINIO_ROOT_PASSWORD=yourpassword" \--name minio \minio/minio server /data --console-address ":9001"
-
-p 9000
: API 端口(用于客户端访问)。 -
-p 9001
: 控制台端口(Web 管理界面)。 -
-v /mnt/data:/data
: 将宿主机目录挂载为存储卷(确保/mnt/data
存在)。 -
MINIO_ROOT_USER
和MINIO_ROOT_PASSWORD
: 管理员账号密码。 -
--console-address ":9001"
: 指定控制台端口。
-
-
5、对外开启端口
二、使用源文件安装
-
1、下载源文件
wget https://dl.min.io/server/minio/release/linux-amd64/minio sudo chmod +x minio sudo mv minio /usr/local/bin/
-
2、创建存储目录
sudo mkdir /mnt/data sudo chown -R $USER:$USER /mnt/data
-
3、启动
minio
服务export MINIO_ROOT_USER=admin export MINIO_ROOT_PASSWORD=yourpassword minio server /mnt/data --console-address ":9001"
-
4、守护进程的方式启动
nohup minio server /mnt/data --console-address ":9001" > minio.log 2>&1 &
-
5、设置成系统服务(可选)
[Unit] Description=MinIO After=network.target[Service] User=root Environment="MINIO_ROOT_USER=admin" Environment="MINIO_ROOT_PASSWORD=yourpassword" ExecStart=/usr/local/bin/minio server /mnt/data --console-address ":9001"[Install] WantedBy=multi-user.target
-
启用并启动服务
sudo systemctl enable --now minio
-
三、在gin
中集成minio
文件存储
-
1、在
minio
可视化界面创建一个Buckets
用于文件存储 -
2、创建
AccessKeyID
和SecretAccessKey
-
3、安装依赖包
go get github.com/minio/minio-go/v7
-
4、下面实现上传、下载文件、生成文件地址的方式
package mainimport ("context""fmt""io""log""net/http""path/filepath""time""github.com/gin-gonic/gin""github.com/minio/minio-go/v7""github.com/minio/minio-go/v7/pkg/credentials" )// MinIO 配置 const (minioEndpoint = "123.xx.229:9000" // 替换为你的 MinIO 地址minioAccessKeyID = "HZKH0JJxx8NRRASWVT" // 替换为你的 Access KeyminioSecretAccessKey = "YASffM8CLzoq6zxgZjDS1N2Av4o" // 替换为你的 Secret KeyminioUseSSL = falseminioBucketName = "test1" // 替换为你的 Bucket 名称 )var minioClient *minio.Clientfunc init() {// 初始化 MinIO 客户端var err errorminioClient, err = minio.New(minioEndpoint, &minio.Options{Creds: credentials.NewStaticV4(minioAccessKeyID, minioSecretAccessKey, ""),Secure: minioUseSSL,})if err != nil {log.Fatalf("Failed to initialize MinIO client: %v", err)}// 检查并创建存储桶ctx := context.Background()exists, err := minioClient.BucketExists(ctx, minioBucketName)if err != nil {log.Fatalf("Failed to check bucket existence: %v", err)}if !exists {err = minioClient.MakeBucket(ctx, minioBucketName, minio.MakeBucketOptions{})if err != nil {log.Fatalf("Failed to create bucket: %v", err)}log.Printf("Bucket %s created successfully", minioBucketName)} }func main() {r := gin.Default()// 上传图片接口r.POST("/upload", uploadImage)// 下载图片接口r.GET("/download/:filename", downloadImage)// 生成30天有效的临时链接objectName := "trailer.mp4"url, err := minioClient.PresignedGetObject(context.Background(), minioBucketName, objectName, 7*24*time.Hour, nil)if err != nil {log.Fatalf("生成链接失败: %v", err)}fmt.Println("地址", url.String())// 启动服务r.Run(":8080") }// 上传图片处理函数 func uploadImage(c *gin.Context) {// 从表单中获取文件file, err := c.FormFile("file")if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 打开文件fileReader, err := file.Open()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}defer fileReader.Close()// 上传到 MinIOctx := context.Background()objectName := fmt.Sprintf("%d-%s", time.Now().Unix(), file.Filename)contentType := "application/octet-stream"if filepath.Ext(file.Filename) == ".jpg" || filepath.Ext(file.Filename) == ".jpeg" {contentType = "image/jpeg"} else if filepath.Ext(file.Filename) == ".png" {contentType = "image/png"}_, err = minioClient.PutObject(ctx, minioBucketName, objectName, fileReader, file.Size, minio.PutObjectOptions{ContentType: contentType,})if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, gin.H{"message": "Image uploaded successfully","objectName": objectName,}) }// 下载图片处理函数 func downloadImage(c *gin.Context) {filename := c.Param("filename")// 从 MinIO 获取对象ctx := context.Background()object, err := minioClient.GetObject(ctx, minioBucketName, filename, minio.GetObjectOptions{})if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}defer object.Close()// 获取对象信息objInfo, err := object.Stat()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}// 设置响应头c.Header("Content-Disposition", "attachment; filename="+filename)c.Header("Content-Type", objInfo.ContentType)c.Header("Content-Length", fmt.Sprintf("%d", objInfo.Size))// 流式传输文件内容c.Stream(func(w io.Writer) bool {_, err := io.Copy(w, object)if err != nil {return false}return true}) }