gin结合minio来做文件存储

一、使用docker安装

  • 1、安装docker

    properties 复制代码
    sudo apt update
    sudo apt install -y docker.io
    sudo systemctl enable --now docker
  • 2、配置自己的阿里云镜像,连接地址

  • 3、拉取镜像

    properties 复制代码
    sudo docker pull minio/minio
  • 4、创建容器

    properties 复制代码
    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_USERMINIO_ROOT_PASSWORD: 管理员账号密码。

    • --console-address ":9001": 指定控制台端口。

  • 5、对外开启端口

二、使用源文件安装

  • 1、下载源文件

    properties 复制代码
    wget https://dl.min.io/server/minio/release/linux-amd64/minio
    sudo chmod +x minio
    sudo mv minio /usr/local/bin/
  • 2、创建存储目录

    properties 复制代码
    sudo mkdir /mnt/data
    sudo chown -R $USER:$USER /mnt/data
  • 3、启动minio服务

    properties 复制代码
    export MINIO_ROOT_USER=admin
    export MINIO_ROOT_PASSWORD=yourpassword
    minio server /mnt/data --console-address ":9001"
  • 4、守护进程的方式启动

    properties 复制代码
    nohup minio server /mnt/data --console-address ":9001" > minio.log 2>&1 &
  • 5、设置成系统服务(可选)

    properties 复制代码
    [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
    • 启用并启动服务

      properties 复制代码
      sudo systemctl enable --now minio

三、在gin中集成minio文件存储

  • 1、在minio可视化界面创建一个Buckets用于文件存储

  • 2、创建AccessKeyIDSecretAccessKey


  • 3、安装依赖包

    properties 复制代码
    go get github.com/minio/minio-go/v7
  • 4、下面实现上传、下载文件、生成文件地址的方式

    go 复制代码
    package main
    
    import (
    	"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 Key
    	minioSecretAccessKey = "YASffM8CLzoq6zxgZjDS1N2Av4o" // 替换为你的 Secret Key
    	minioUseSSL          = false
    	minioBucketName      = "test1" // 替换为你的 Bucket 名称
    )
    
    var minioClient *minio.Client
    
    func init() {
    	// 初始化 MinIO 客户端
    	var err error
    	minioClient, 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()
    
    	// 上传到 MinIO
    	ctx := 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
    	})
    }
相关推荐
坐吃山猪18 分钟前
SpringBoot01-配置文件
java·开发语言
我叫汪枫42 分钟前
《Java餐厅的待客之道:BIO, NIO, AIO三种服务模式的进化》
java·开发语言·nio
yaoxtao1 小时前
java.nio.file.InvalidPathException异常
java·linux·ubuntu
Swift社区2 小时前
从 JDK 1.8 切换到 JDK 21 时遇到 NoProviderFoundException 该如何解决?
java·开发语言
DKPT3 小时前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring
phltxy3 小时前
JVM——Java虚拟机学习
java·jvm·学习
seabirdssss5 小时前
使用Spring Boot DevTools快速重启功能
java·spring boot·后端
喂完待续5 小时前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
benben0445 小时前
ReAct模式解读
java·ai