Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: oss 上传添加 minio 支持 #1699

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
203 changes: 203 additions & 0 deletions server/component/minio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package component

import (
"context"
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/config"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/pkg/errors"
"mime/multipart"
"os"
"path"
"path/filepath"
"strings"
"time"
)

/*
* @Author <bypanghu> ([email protected])
* @Date 2023/12/27 17:16
**/

var MinioPkg = new(minioPkg)

type minioPkg struct {
conf *config.Minio
}

func (m *minioPkg) Init(minio *config.Minio) {
defer func() {
if r := recover(); r != nil {
println("minio init error")
}
}()
m.conf = minio
}

func (m *minioPkg) NewClient() (*minio.Client, error) {
if m.conf == nil {
panic("please make minio init first")
}
client, err := minio.New(m.conf.EndPoint, &minio.Options{
Creds: credentials.NewStaticV4(m.conf.AccessKey, m.conf.SecretKey, m.conf.Token),
Secure: m.conf.UseSSl,
})
if err != nil {
return nil, errors.Wrap(err, "[oss][minio]获取minio.Client对象失败!")
}
return client, nil
}

// Filepath 访问全路径
func (m *minioPkg) Filepath(key string, bucket string) string {
if m.conf == nil {
panic("please make minio init first")
}
return m.conf.Domain + path.Join(bucket, key)
}

// Filename 格式化文件名
func (m *minioPkg) Filename(filename string) string {
if m.conf == nil {
panic("please make minio init first")
}
names := strings.Split(filename, string(os.PathSeparator))
filename = names[len(names)-1:][0]
if m.conf.Prefix == "" {
return fmt.Sprintf("%s", filename)
}
return fmt.Sprintf("%s_%s", m.conf.Prefix, filename)
}

// FileKey 文件key
func (m *minioPkg) FileKey(filename string) string {
if m.conf == nil {
panic("please make minio init first")
}
return filepath.Join(m.conf.Path, time.Now().Format("2006-01-02"), filename)
}

func (m *minioPkg) FileKeyWithTime(filename string) string {
if m.conf == nil {
panic("please make minio init first")
}
return filepath.Join(time.Now().Format("2006-01-02"), m.Filename(filename))
}

func (m *minioPkg) UploadByFile(ctx context.Context, file *os.File, bucket string) (filepath string, filename string, err error) {
if m.conf == nil {
panic("please make minio init first")
}
var client *minio.Client
client, err = m.NewClient()
if err != nil {
return filepath, filename, err
}
err = m.MakeBucket(ctx, bucket)
if err != nil {
return filepath, filename, err
}
filename = m.Filename(file.Name())
key := m.FileKey(filename)
filepath = m.Filepath(key, bucket)
info, _ := file.Stat()
options := minio.PutObjectOptions{}
_, err = client.PutObject(ctx, bucket, key, file, info.Size(), options)
if err != nil {
return filepath, filename, errors.Wrap(err, "[oss][minio]文件上传失败!")
}
return filepath, filename, nil
}

func (m *minioPkg) UploadByHeader(ctx context.Context, header *multipart.FileHeader, bucket string) (filepath string, filename string, err error) {
if m.conf == nil {
panic("please make minio init first")
}
var client *minio.Client
client, err = m.NewClient()
if err != nil {
return filepath, filename, err
}
err = m.MakeBucket(ctx, bucket)
if err != nil {
return filepath, filename, err
}
filename = m.Filename(header.Filename)

filename = fmt.Sprintf("%d-%s", time.Now().Unix(), filename)

key := m.FileKey(filename)
filepath = m.Filepath(key, bucket)
// 生成时间戳
time.Now().Unix()

options := minio.PutObjectOptions{ContentType: header.Header.Get("content-type")}

var file multipart.File
file, err = header.Open()
if err != nil {
return filepath, filename, errors.Wrap(err, "通过header获取io.Reader对象失败!")
}
_, err = client.PutObject(ctx, bucket, key, file, header.Size, options)
if err != nil {
return filepath, filename, errors.Wrap(err, "[oss][minio]文件上传失败!")
}
return filepath, filename, nil
}

func (m *minioPkg) UploadByFilePath(ctx context.Context, file string, bucket string) (filepath string, filename string, err error) {
if m.conf == nil {
panic("please make minio init first")
}
var client *minio.Client
client, err = m.NewClient()
if err != nil {
return filepath, filename, err
}
err = m.MakeBucket(ctx, bucket)
if err != nil {
return filepath, filename, err
}
filename = m.Filename(file)
key := m.FileKey(filename)
filepath = m.Filepath(key, bucket)
// 获取文件
fileFile, err := os.OpenFile(file, os.O_RDONLY, 0755)
if err != nil {
return filepath, filename, errors.Wrap(err, "[oss][minio]文件上传失败!")
}
info, _ := fileFile.Stat()
options := minio.PutObjectOptions{}
_, err = client.PutObject(ctx, bucket, key, fileFile, info.Size(), options)
if err != nil {
return filepath, filename, errors.Wrap(err, "[oss][minio]文件上传失败!")
}
return filepath, filename, nil
}

func (m *minioPkg) MakeBucket(ctx context.Context, bucket string) error {
if m.conf == nil {
panic("please make minio init first")
}
var client *minio.Client
client, err := m.NewClient()
if err != nil {
return err
}
var exists bool
exists, err = client.BucketExists(ctx, bucket)
if !exists && err == nil {
options := minio.MakeBucketOptions{}
err = client.MakeBucket(ctx, bucket, options)
if err != nil {
return errors.Wrapf(err, "[oss][minio][bucket:%s]存储桶创建失败!", bucket)
}
policy := fmt.Sprintf("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::%s\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\"],\"Resource\":[\"arn:aws:s3:::%s/*\"]}]}", bucket, bucket)
err = client.SetBucketPolicy(ctx, bucket, policy)
if err != nil {
return errors.Wrapf(err, "[oss][minio][bucket:%s]设置存储桶权限失败!", bucket)
}
}
return nil
}
14 changes: 13 additions & 1 deletion server/config.docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,18 @@ hua-wei-obs:
access-key: you-access-key
secret-key: you-secret-key

# minio oss configuration
minio:
access_key: ""
domain:
end_point:
path:
prefix:
token: ""
use_ssl: true
secret_key: ""


# excel configuration
excel:
dir: ./resource/excel/
Expand Down Expand Up @@ -217,4 +229,4 @@ cors:
allow-headers: content-type
allow-methods: GET, POST
expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
allow-credentials: true # 布尔值
allow-credentials: true # 布尔值
11 changes: 11 additions & 0 deletions server/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,17 @@ hua-wei-obs:
access-key: you-access-key
secret-key: you-secret-key

# minio oss configuration
minio:
access_key: ""
domain:
end_point:
path:
prefix:
token: ""
use_ssl: true
secret_key: ""

# excel configuration
excel:
dir: ./resource/excel/
Expand Down
3 changes: 3 additions & 0 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ type Server struct {
HuaWeiObs HuaWeiObs `mapstructure:"hua-wei-obs" json:"hua-wei-obs" yaml:"hua-wei-obs"`
TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencent-cos" yaml:"tencent-cos"`
AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"`
// minio 配置
Minio Minio `mapstructure:"minio" json:"minio" yaml:"minio"`

Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`

// 跨域配置
Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"`

}
17 changes: 17 additions & 0 deletions server/config/oss_minio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package config

/*
* @Author <bypanghu> ([email protected])
* @Date 2023/12/27 17:05
**/

type Minio struct {
AccessKey string `json:"access_key" yaml:"access_key" mapstructure:"access_key" `
Domain string `json:"domain" yaml:"domain" mapstructure:"domain"`
EndPoint string `json:"end_point" yaml:"end_point" mapstructure:"end_point"`
Path string `json:"path" yaml:"path" mapstructure:"path"`
Prefix string `json:"prefix" yaml:"prefix" mapstructure:"prefix"`
Token string `json:"token" yaml:"token" mapstructure:"token"`
UseSSl bool `json:"use_ssl" yaml:"use_ssl" mapstructure:"use_ssl"`
SecretKey string `json:"secret_key" yaml:"secret_key" mapstructure:"secret_key"`
}
20 changes: 13 additions & 7 deletions server/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/flipped-aurora/gin-vue-admin/server

go 1.20
go 1.21

toolchain go1.22.0

require (
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible
Expand All @@ -18,6 +20,7 @@ require (
github.com/gookit/color v1.5.4
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible
github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84
github.com/minio/minio-go/v7 v7.0.69
github.com/mojocn/base64Captcha v1.3.5
github.com/otiai10/copy v1.7.0
github.com/pkg/errors v0.9.1
Expand All @@ -38,7 +41,7 @@ require (
go.mongodb.org/mongo-driver v1.12.1
go.uber.org/automaxprocs v1.5.3
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.16.0
golang.org/x/crypto v0.19.0
golang.org/x/sync v0.5.0
golang.org/x/text v0.14.0
gorm.io/driver/mysql v1.5.6
Expand Down Expand Up @@ -75,7 +78,7 @@ require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
Expand All @@ -85,14 +88,16 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/microsoft/go-mssqldb v1.1.0 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand All @@ -105,6 +110,7 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
Expand All @@ -127,8 +133,8 @@ require (
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/image v0.11.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/time v0.1.0 // indirect
golang.org/x/tools v0.16.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
Expand Down