本篇主要介绍Go开发minio存储文件服务的过程. 篇幅有点长.
要实现的功能, 如下:
鉴权(jwt、casbin)
注释文档(swagger)
MinioSDK(minio)
集成部署(jenkins, docker)
代码↓:
Github
前端 https://github.com/guangnaoke/vue3-admin
Go https://github.com/guangnaoke/go-minio
Gitee
前端 https://gitee.com/Xiao_Yi_Zhou/vue3-admin.git
Go https://gitee.com/Xiao_Yi_Zhou/go-minio.git
第一部分链接: 前后端CI/CD, GO编写minio存储文件服务 (一)
都是些比较简单的功能. 那么… 开整!
安装
GO安装库及插件
go get -u github.com/gin-gonic/gin
go get github.com/casbin/casbin/v2
go get github.com/golang-jwt/jwt
go get github.com/minio/minio-go/v7
go get github.com/swaggo/gin-swagger
go get github.com/swaggo/swag
go get gopkg.in/yaml.v3
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
docker安装Minio
docker run \
-d \
-p 9000:9000 \
-p 9001:9001 \
--name minio \
--restart=always \
-v /www/minio/data:/data \
-e "MINIO_ROOT_USER=YOURNAME" \
-e "MINIO_ROOT_PASSWORD=YOURPASSWORD" \
minio/minio:latest server /data --console-address ":9001"
MINIO_ROOT_USER, MINIO_ROOT_PASSWORD 账号密码改成自己的
浏览器输入地址: http://127.0.0.1(替换地址):9001 看是否能打开minio控制端
账号密码就是刚才设置的. 现在可以建个bucket试试传输文件之类的.
查看SDK列表页
SDK列表 https://docs.min.io/docs/golang-client-api-reference.html
例子 https://github.com/minio/minio-go/tree/master/examples/s3
需要实现的接口不多, 以下:
ListBuckets
存储桶列表ListObjects
桶内文件列表PutObject
上传文件RemoveObject
删除文件PresignedGetObject
获取URL下载
删除桶之类的还是管理员去操作, 以免误删. 前端只需要上传和查看功能.
docker安装Mysql
docker run \
-p 3306:3306 \
--name mysql \
--privileged=true \
--restart=always \
-v /usr/mysql/local/conf:/etc/mysql/conf.d \
-v /usr/mysql/local/logs:/logs \
-v /usr/mysql/local/data:/var/lib/mysql \
-v /usr/mysql/local/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=yourpassword \
-e TZ=Asia/Shanghai \
-d docker.io/mysql:latest
–privileged=true 【容器内的root拥有真正的权限, 否则只是普通用户权限】
-v 【挂载目录, 配置文件, 日志】
MYSQL_ROOT_PASSWORD 改成自己的密码
查看容器看是否运行成功
通过Navicat之类的工具看是否能正常连接数据库.
初始化配置信息
根目录创建conf文件夹.
创建conf.yaml, 把配置信息写入conf.yaml文件.
# Mysql服务配置
mysql:
driverName: mysql
host: 127.0.0.1
port: 3306
database: you_database
username: admin
password: admin
charset: utf8mb4
parseTime: True
loc: Local
# MinIO文件存储服务器配置
minio:
endpoint: 127.0.0.1:9000
access: you_access
accessKey: admin
secretKey: admin
初始化全局单例
创建config.go, 这些都是程序初始化时要用到的模型, mysql的配置信息、minio账号配置等.
package conf
type MysqlConf struct {
DriverName string `yaml:"driverName" json:"driver_name"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
Host string `yaml:"host" json:"host"`
Port string `yaml:"port" json:"port"`
Database string `yaml:"database" json:"database"`
Charset string `yaml:"charset" json:"charset"`
ParseTime string `yaml:"parseTime" json:"parse_time"`
Loc string `yaml:"loc" json:"loc"`
}
type MinioConf struct {
Endpoint string `yaml:"endpoint" json:"endpoint"`
Access string `yaml:"access" json:"access"`
AccessKey string `yaml:"accessKey" json:"accessKey"`
SecretKey string `yaml:"secretKey" json:"secretKey"`
}
type ServerConf struct {
MysqlInfo MysqlConf `yaml:"mysql" json:"mysql"`
MinioInfo MinioConf `yaml:"minio" json:"minio"`
}
创建global文件夹.
创建singleton.go, 设置全局单例.
package global
import (
"minio_server/conf"
"github.com/minio/minio-go/v7"
"gorm.io/gorm"
)
var (
Settings conf.ServerConf
DB *gorm.DB
MinioClient *minio.Client
)
创建一个initialize文件夹.
创建config.go, 将之前的yaml配置信息设置到全局serverConfig, 下面会用到.
package initialize
import (
"io/ioutil"
"log"
"minio_server/conf"
"minio_server/global"
"os"
"gopkg.in/yaml.v3"
)
func InitConfig() error {
workDor, _ := os.Getwd()
// 读取yaml配置文件
yamlFile, err := ioutil.ReadFile(workDor + "/conf/conf.yaml")
if err != nil {
log.Printf("yamlFile.Get err %v", err)
return err
}
// 配置信息模型
serverConfig := conf.ServerConf{
}
// 将yaml文件对应的配置信息写入serverConfig
err = yaml.Unmarshal(yamlFile, &serverConfig)
if err != nil {
log.Fatalf("Unmarshal: %v", err)
return err
}
// 设置全局Settings
global.Settings = serverConfig
return nil
}
创建mysql.go
package initialize
import (
"database/sql"
"fmt"
"log"
"minio_server/global"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
func InitMysqlDB() error {
mysqlInfo := global.Settings.MysqlInfo
args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=%s&loc=%s",
mysqlInfo.Username,
mysqlInfo.Password,
mysqlInfo.Host,
mysqlInfo.Port,
mysqlInfo.Database,
mysqlInfo.Charset,
mysqlInfo.ParseTime,
mysqlInfo.Loc,
)
sqlDB, err := sql.Open(mysqlInfo.DriverName, args)
if err != nil {
log.Fatalln(err)
return err
}
// 空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// 打开数据库连接的最大数量, 根据需求看着调
sqlDB.SetMaxOpenConns(100)
// 连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)
// 注册单例
gormDB, err := gorm.Open(mysql.New(mysql.Config{
Conn: sqlDB,
}), &gorm.Config{
// 禁止自动给表名加 "s"
NamingStrategy: schema.NamingStrategy{
SingularTable: true},
})
if err != nil {
global.DB = nil
log.Fatalln(err)
return err
}
// 设置全局DB
global.DB = gormDB
log.Println("Mysql Init Success")
return nil
}
创建minio.go
package initialize
import (
"log"
"minio_server/global"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
func InitMinIO() error {
minioInfo := global.Settings.MinioInfo
// 创建minio服务, 传入IP、账号、密码.
minioClient, err := minio.New(minioInfo.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(minioInfo.AccessKey, minioInfo.SecretKey, ""),
// 关闭TLS, 暂时不需要
Secure: false,
})
if err != nil {
global.MinioClient = nil
log.Fatalln(err)
return err
}
// 设置全局MinioClient
global.MinioClient = minioClient
log.Println("Minio Init Success")
return nil
}
创建init.go, 将需要初始化配置的应用统一封装到init文件.
package initialize
func Init() {
errConf := InitConfig()
if errConf != nil {
panic(errConf)
}
errSql := InitMysqlDB()
if errSql != nil {
panic(errSql)
}
errMinio := InitMinIO()
if errMinio != nil {
panic(errMinio)
}
}
SDK封装
接下来写点SDK相关的代码.
创建models文件夹.
创建user.go, 按照字段去mysql数据库里面创建一些要用的账号密码. Level分1-3级, 根据自己需求配置.
package models
import "time"
type User struct {
UserID int16 `sql:"user_id" json:"user_id"` // 用户ID
Access string `sql:"access" json:"access"` // 用户权限
AccessKey string `sql:"access_key" json:"access_key"` // 用户名称
SecretKey string `sql:"secret_key" json:"secret_key"` // 用户密码
Level int `sql:"level" json:"level"` // 用户等级
CreateTime time.Time `sql:"create_time" json:"create_time"` // 创建时间
UpdateTime time.Time `sql:"update_time" json:"update_time"` // 更新时间
}
JWT
创建common文件夹.
创建jwt.go
package common
import (
"minio_server/models"
"time"
"github.com/golang-jwt/jwt"
)
var jwtKey = []byte("your_key")
type Claims struct {
UserID int64
Access string
AccessKey string
Level int
jwt.StandardClaims
}
// 颁发token
func ReleaseToken(user models.User) (string, error) {
expirationTime := time.Now().Add(7 * 24 * time.Hour)
claims := &Claims{
UserID: user.UserID, // 用户id
Access: user.Access, // 用户权限
AccessKey: user.AccessKey, // 用户账号
Level: user.Level, // 等级
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(), // 过期时间
IssuedAt: time.Now().Unix(), // 签发时间
Issuer: "minio", // 签发人
Subject: "token", // 标题
},
}
// 加密
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtKey)
if err != nil {
return "", err
}
return tokenString, nil
}
// 解析token
func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
claims := &Claims{
}
token, err := jwt.ParseWithClaims(tokenString, claims