初始化配置
文章目录
- 初始化配置
- 一、配置yaml文件
- 二、Go读取配置文件
- 三、初始化日志Logger
- 四、初始化数据库(MySQL或SqlLite)
- 五、初始化缓存(Redis)
- 六、中间件服务(middleware)
一、配置yaml文件
Server:
Mode: debug # 服务器模式,可选值为 debug 或 release
Port: :8765 # 服务器端口号
DbType: "mysql" # 数据库类型,可选值为 mysql 或 sqlite
DbAutoMigrate: true # 是否自动迁移数据库表结构,如果表结构没有变化,可以设为 false 提高启动速度
DbLogMode: "error" # 数据库日志级别,可选值有 silent, error, warn, info, 默认为 info
JWT: # JWT 鉴权配置
Secret: "abc123321" # JWT 密钥
Expire: 24 # JWT 过期时间,单位为小时
Issuer: "gin-vue-blog" # JWT 签发者
Mysql: # MySQL 数据库配置
Host: "127.0.0.1" # MySQL 主机地址
Port: "3306" # MySQL 端口号
Config: "charset=utf8mb4&parseTime=True&loc=Local" # MySQL 配置,例如字符集和时区设置
Dbname: "gvb" # MySQL 数据库名称
Username: "root" # MySQL 用户名
Password: "123456" # MySQL 密码
Sqlite: # SQLite 数据库配置
Dsn: "gvb.db" # SQLite 数据库文件路径
Redis: # Redis 缓存配置
DB: 0 # Redis 数据库索引
Addr: '' # Redis 服务器地址
Password: '' # Redis 访问密码,如果没有设置密码则留空
Session: # 会话(Session)配置
Name: "mysession" # 会话名称
Salt: "salt" # 加密盐
MaxAge: 600 # 会话过期时间,单位为秒
Log: # 日志配置
Level: "debug" # 日志级别,可选值有 debug, info, warn, error
Format: "text" # 日志格式,可选值有 text, json
Directory: "log" # 日志存储目录
Email: # 邮件发送配置
Host: "smtp.qq.com" # SMTP 服务器地址
Port: 465 # SMTP 服务器端口号
From: "" # 发件人邮箱
IsSSL: true # 是否开启 SSL
Secret: "" # SMTP 密钥
Nickname: "" # 发件人昵称
Captcha: # 验证码配置
SendEmail: true # 是否通过邮件发送验证码
ExpireTime: 5 # 验证码过期时间,单位为分钟
Upload: # 文件上传配置
OssType: "qiniu" # 文件上传类型,可选值为 local 或 qiniu
Path: "public/uploaded" # 本地文件访问路径,OssType="local" 生效
StorePath: "../public/uploaded" # 本地文件上传路径,相对于 main.go,OssType="local" 生效
Qiniu: # 七牛云存储配置
ImgPath: "" # 外链
Zone: "z1" # 存储区域,可选值有 z0, z1, z2, na0, as0
Bucket: "" # 存储空间名称
AccessKey: "-" # 七牛云 AccessKey
SecretKey: "" # 七牛云 SecretKey
UseHttps: false # 是否使用 HTTPS 协议进行图片上传和访问
UseCdnDomains: false # 是否使用七牛云 CDN 加速域名
二、Go读取配置文件
1.结构体的定义
type Config struct {
Server struct {
Mode string // debug | release
Port string
DbType string // mysql | sqlite
DbAutoMigrate bool // 是否自动迁移数据库表结构
DbLogMode string // silent | error | warn | info
}
Log struct {
Level string // debug | info | warn | error
Prefix string
Format string // text | json
Directory string
}
JWT struct {
Secret string
Expire int64 // hour
Issuer string
}
Mysql struct {
Host string // 服务器地址
Port string // 端口
Config string // 高级配置
Dbname string // 数据库名
Username string // 数据库用户名
Password string // 数据库密码
}
SQLite struct {
Dsn string // Data Source Name
}
Redis struct {
DB int // 指定 Redis 数据库
Addr string // 服务器地址:端口
Password string // 密码
}
Session struct {
Name string
Salt string
MaxAge int
}
Email struct {
To string // 收件人 多个以英文逗号分隔 例:a@qq.com,b@qq.com
From string // 发件人 要发邮件的邮箱
Host string // 服务器地址, 例如 smtp.qq.com 前往要发邮件的邮箱查看其 smtp 协议
Secret string // 密钥, 不是邮箱登录密码, 是开启 smtp 服务后获取的一串验证码
Nickname string // 发件人昵称, 通常为自己的邮箱名
Port int // 前往要发邮件的邮箱查看其 smtp 协议端口, 大多为 465
IsSSL bool // 是否开启 SSL
}
Captcha struct {
SendEmail bool // 是否通过邮箱发送验证码
ExpireTime int // 过期时间
}
Upload struct {
// Size int // 文件上传的最大值
OssType string // local | qiniu
Path string // 本地文件访问路径
StorePath string // 本地文件存储路径
}
Qiniu struct {
ImgPath string // 外链链接
Zone string // 存储区域
Bucket string // 空间名称
AccessKey string // 秘钥AK
SecretKey string // 秘钥SK
UseHTTPS bool // 是否使用https
UseCdnDomains bool // 上传是否使用 CDN 上传加速
}
}
2.从指定路径中读取配置信息到结构体里面
// 定义一个Public的变量
var Conf *Config
func GetConfig() *Config {
if Conf == nil {
log.Panic("配置文件未初始化")
return nil
}
return Conf
}
// 从指定路径读取配置文件
func ReadConfig(path string) *Config {
v := viper.New()
v.SetConfigFile(path)
v.AutomaticEnv() // 允许使用环境变量
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // SERVER_APPMODE => SERVER.APPMODE
if err := v.ReadInConfig(); err != nil {
panic("配置文件读取失败: " + err.Error())
}
if err := v.Unmarshal(&Conf); err != nil {
panic("配置文件反序列化失败: " + err.Error())
}
log.Println("配置文件内容加载成功: ", path)
return Conf
}
// 数据库类型
func (*Config) DbType() string {
if Conf.Server.DbType == "" {
Conf.Server.DbType = "sqlite"
}
return Conf.Server.DbType
}
// 数据库连接字符串
func (*Config) DbDSN() string {
switch Conf.Server.DbType {
case "mysql":
conf := Conf.Mysql
return fmt.Sprintf(
"%s:%s@tcp(%s:%s)/%s?%s",
conf.Username, conf.Password, conf.Host, conf.Port, conf.Dbname, conf.Config,
)
case "sqlite":
return Conf.SQLite.Dsn
// 默认使用 sqlite, 并且使用内存数据库
default:
Conf.Server.DbType = "sqlite"
if Conf.SQLite.Dsn == "" {
Conf.SQLite.Dsn = "file::memory:"
}
return Conf.SQLite.Dsn
}
}
三、初始化日志Logger
在1.21.0版本后,go添加了slog的结构化日志库。故使用轻量级的日志库。
func InitLogger(conf *g.Config) *slog.Logger {
var level slog.Level
// 设置日志级别
switch conf.Log.Level {
case "debug":
level = slog.LevelDebug
case "info":
level = slog.LevelInfo
case "warn":
level = slog.LevelWarn
case "error":
level = slog.LevelError
default:
level = slog.LevelInfo
}
option := &slog.HandlerOptions{
AddSource: true, // 是否显示代码详细位置
Level: level,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey {
if t, ok := a.Value.Any().(time.Time); ok {
a.Value = slog.StringValue(t.Format(time.DateTime))
}
}
return a
},
}
var handler slog.Handler
switch conf.Log.Format {
case "json":
handler = slog.NewJSONHandler(os.Stdout, option)
case "text":
fallthrough
default: //默认text
handler = slog.NewTextHandler(os.Stdout, option)
}
loggers := slog.New(handler)
slog.SetDefault(loggers)
return loggers
}
四、初始化数据库(MySQL或SqlLite)
func InitDatabase(conf *g.Config) *gorm.DB {
dbtype := conf.DbType() // 数据库类型
dsn := conf.DbDSN() //DSN
var db *gorm.DB
var err error
var level logger.LogLevel
switch conf.Server.DbLogMode {
case "silent":
level = logger.Silent
case "info":
level = logger.Info
case "warn":
level = logger.Warn
case "error":
fallthrough
default:
level = logger.Error
}
config := &gorm.Config{
Logger: logger.Default.LogMode(level),
DisableForeignKeyConstraintWhenMigrating: true, // 禁用外键约束
SkipDefaultTransaction: true, // 禁用默认事务(提高运行速度)
NamingStrategy: schema.NamingStrategy{
SingularTable: true, // 单数表名
},
}
switch dbtype {
case "mysql":
db, err = gorm.Open(mysql.Open(dsn), config)
case "sqlite":
db, err = gorm.Open(sqlite.Open(dsn), config)
default:
log.Fatal("不支持的数据库类型: ", dbtype)
}
if err != nil {
log.Fatal("数据库连接失败", err)
}
log.Println("数据库连接成功", dbtype, dsn)
if conf.Server.DbAutoMigrate {
if err := model.MakeMigrate(db); err != nil {
log.Fatal("数据库迁移失败", err)
}
log.Println("数据库自动迁移成功")
}
return db
}
五、初始化缓存(Redis)
func InitRedis(conf *g.Config) *redis.Client {
rdb := redis.NewClient(&redis.Options{
Addr: conf.Redis.Addr,
Password: conf.Redis.Password,
DB: conf.Redis.DB,
})
_, err := rdb.Ping(context.Background()).Result()
if err != nil {
log.Fatal("Redis 连接失败: ", err)
}
log.Println("Redis 连接成功", conf.Redis.Addr, conf.Redis.DB, conf.Redis.Password)
return rdb
}
六、中间件服务(middleware)
1.跨域请求
func CORS() gin.HandlerFunc {
return cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"PUT", "POST", "GET", "DELETE", "OPTIONS", "PATCH"},
AllowHeaders: []string{"Origin", "Authorization", "Content-Type", "X-Requested-With"},
ExposeHeaders: []string{"Content-Type"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return true
},
MaxAge: 24 * time.Hour,
})
}
2.绑定db,将*gorm.DB绑定到context的g.CTX_DB键上
func WithGormDB(db *gorm.DB) gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Set(g.CTX_DB, db)
ctx.Next()
}
}
3.绑定Redis
func WithRedisDB(rdb *redis.Client) gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Set(g.CTX_RDB, rdb)
ctx.Next()
}
}
4.设置cookie,用于在请求和响应之间存储会话信息
func WithCookieStore(name, secret string) gin.HandlerFunc {
store := cookie.NewStore([]byte(secret))
store.Options(sessions.Options{Path: "/", MaxAge: 600})
return sessions.Sessions(name, store)
}