diff --git a/server/config.yaml b/server/config.yaml index 1c3eed11f..c3ef82880 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -194,6 +194,16 @@ qiniu: secret-key: "" use-cdn-domains: false +# minio oss configuration +minio: + endpoint: yourEndpoint + access-key-id: yourAccessKeyId + access-key-secret: yourAccessKeySecret + bucket-name: yourBucketName + use-ssl: false + base-path: "" + bucket-url: "http://host:9000/yourBucketName" + # aliyun oss configuration aliyun-oss: endpoint: yourEndpoint diff --git a/server/config/config.go b/server/config/config.go index 6519333cb..15da9c7db 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -26,6 +26,7 @@ type Server struct { TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencent-cos" yaml:"tencent-cos"` AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"` CloudflareR2 CloudflareR2 `mapstructure:"cloudflare-r2" json:"cloudflare-r2" yaml:"cloudflare-r2"` + Minio Minio `mapstructure:"minio" json:"minio" yaml:"minio"` Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"` diff --git a/server/config/oss_minio.go b/server/config/oss_minio.go new file mode 100644 index 000000000..a0faac74a --- /dev/null +++ b/server/config/oss_minio.go @@ -0,0 +1,11 @@ +package config + +type Minio struct { + Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"` + AccessKeyId string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"` + AccessKeySecret string `mapstructure:"access-key-secret" json:"access-key-secret" yaml:"access-key-secret"` + BucketName string `mapstructure:"bucket-name" json:"bucket-name" yaml:"bucket-name"` + UseSSL bool `mapstructure:"use-ssl" json:"use-ssl" yaml:"use-ssl"` + BasePath string `mapstructure:"base-path" json:"base-path" yaml:"base-path"` + BucketUrl string `mapstructure:"bucket-url" json:"bucket-url" yaml:"bucket-url"` +} diff --git a/server/go.mod b/server/go.mod index c5206c92a..66456b30e 100644 --- a/server/go.mod +++ b/server/go.mod @@ -81,6 +81,7 @@ require ( github.com/gammazero/toposort v0.1.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/go-ini/ini v1.67.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect @@ -119,6 +120,8 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/microsoft/go-mssqldb v1.7.2 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.78 // 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 @@ -135,6 +138,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.4 // indirect + github.com/rs/xid v1.6.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect diff --git a/server/go.sum b/server/go.sum index 8fb71e2c2..51e2b9e6f 100644 --- a/server/go.sum +++ b/server/go.sum @@ -318,6 +318,7 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -359,6 +360,10 @@ github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60V github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.78 h1:LqW2zy52fxnI4gg8C2oZviTaKHcBV36scS+RzJnxUFs= +github.com/minio/minio-go/v7 v7.0.78/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -437,6 +442,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= diff --git a/server/utils/upload/minio_oss.go b/server/utils/upload/minio_oss.go new file mode 100644 index 000000000..f56cb5cbf --- /dev/null +++ b/server/utils/upload/minio_oss.go @@ -0,0 +1,79 @@ +package upload + +import ( + "context" + "errors" + "mime/multipart" + "path/filepath" + "strings" + "time" + + "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/utils" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "go.uber.org/zap" +) + +var MinioClient *Minio // 优化性能,但是不支持动态配置,如果修改了minio配置,需要重启后端 + +type Minio struct { + client *minio.Client + bucket string +} + +func GetMinio(endpoint, accessKeyID, secretAccessKey, bucketName string, useSSL bool) (*Minio, error) { + if MinioClient != nil { + return MinioClient, nil + } + // Initialize minio client object. + minioClient, err := minio.New(endpoint, &minio.Options{ + Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), + Secure: useSSL, // Set to true if using https + }) + if err != nil { + return nil, err + } + // 尝试创建bucket + err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{}) + if err != nil { + // Check to see if we already own this bucket (which happens if you run this twice) + exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName) + if errBucketExists == nil && exists { + // log.Printf("We already own %s\n", bucketName) + } else { + return nil, err + } + } + + return &Minio{client: minioClient, bucket: bucketName}, nil +} + +func (m *Minio) UploadFile(file *multipart.FileHeader) (filePathres, key string, uploadErr error) { + + // 读取本地文件。 + f, openError := file.Open() + if openError != nil { + global.GVA_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error())) + return "", "", errors.New("function file.Open() Failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + // 对文件名进行加密存储 + ext := filepath.Ext(file.Filename) + filename := utils.MD5V([]byte(strings.TrimSuffix(file.Filename, ext))) + ext + filePathres = global.GVA_CONFIG.Minio.BasePath + "/" + "uploads" + "/" + time.Now().Format("2006-01-02") + "/" + filename + + // Upload the file with FPutObject + info, err := m.client.PutObject(context.Background(), global.GVA_CONFIG.Minio.BucketName, filePathres, f, file.Size, minio.PutObjectOptions{ContentType: "application/octet-stream"}) + if err != nil { + global.GVA_LOG.Error("上传文件到minio失败", zap.Any("err", err.Error())) + return "", "", errors.New("上传文件到minio失败, err:" + err.Error()) + } + return global.GVA_CONFIG.Minio.BucketUrl + "/" + info.Key, filePathres, nil +} + +func (m *Minio) DeleteFile(key string) error { + // Delete the object from MinIO + err := m.client.RemoveObject(context.Background(), m.bucket, key, minio.RemoveObjectOptions{}) + return err +} diff --git a/server/utils/upload/upload.go b/server/utils/upload/upload.go index 72fa44429..28266ab18 100644 --- a/server/utils/upload/upload.go +++ b/server/utils/upload/upload.go @@ -33,6 +33,13 @@ func NewOss() OSS { return &AwsS3{} case "cloudflare-r2": return &CloudflareR2{} + case "minio": + minioClient, err := GetMinio(global.GVA_CONFIG.Minio.Endpoint, global.GVA_CONFIG.Minio.AccessKeyId, global.GVA_CONFIG.Minio.AccessKeySecret, global.GVA_CONFIG.Minio.BucketName, global.GVA_CONFIG.Minio.UseSSL) + if err != nil { + global.GVA_LOG.Warn("你配置了使用minio,但是初始化失败,请检查minio可用性或安全配置: " + err.Error()) + panic("minio初始化失败") // 建议这样做,用户自己配置了minio,如果报错了还要把服务开起来,使用起来也很危险 + } + return minioClient default: return &Local{} }