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
    	})
    }
相关推荐
2501_9061505617 分钟前
私有部署问卷系统操作实战记录-DWSurvey
java·运维·服务器·spring·开源
better_liang29 分钟前
每日Java面试场景题知识点之-TCP/IP协议栈与Socket编程
java·tcp/ip·计算机网络·网络编程·socket·面试题
niucloud-admin41 分钟前
java服务端——controller控制器
java·开发语言
To Be Clean Coder42 分钟前
【Spring源码】通过 Bean 工厂获取 Bean 的过程
java·后端·spring
Fortunate Chen1 小时前
类与对象(下)
java·javascript·jvm
程序员水自流1 小时前
【AI大模型第9集】Function Calling,让AI大模型连接外部世界
java·人工智能·llm
‿hhh1 小时前
综合交通运行协调与应急指挥平台项目说明
java·ajax·npm·json·需求分析·个人开发·规格说明书
小徐Chao努力1 小时前
【Langchain4j-Java AI开发】06-工具与函数调用
java·人工智能·python
无心水1 小时前
【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器
java·python·性能优化
萧曵 丶1 小时前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized