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
    	})
    }
相关推荐
程序员黑豆4 小时前
Java包装类:基本类型与对象的桥梁
java·前端·ai编程
mldong8 小时前
"applicant" 契约:退回发起人的闭环设计
java·架构
月华路8 小时前
G1 垃圾回收:脏卡队列、记忆集与并发精化线程机制
java·开发语言
gugucoding9 小时前
47. 【Java】Java内存模型(JMM)与可见性
java·开发语言
zww89491119 小时前
校园跑腿系统开发实战指南:从需求分析到上线部署全流程解析
java
Fluxart.ai10 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
名字还没想好☜11 小时前
Java 线上内存泄漏排查实战:jmap 导堆、MAT 找 GC Roots 与四类常见泄漏
java·开发语言·jvm·内存泄漏
IT爱学堂12 小时前
尚硅谷 - 2025年3月Java+AI大模型应用开发
java·开发语言·人工智能
小贤plus13 小时前
SpringBoot 三大核心注解精讲:@ControllerAdvice、@RestControllerAdvice、@Validated 分组校验(实战)
java
吠品13 小时前
Java byte数组与String互转:编码细节与踩坑记录
java·linux·服务器