first commit
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// Package config 负责加载与解析应用配置。
|
||||
// 优先级:默认值 < 配置文件 < 环境变量。
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Config 是应用的顶层配置。
|
||||
type Config struct {
|
||||
Server ServerConfig `mapstructure:"server"`
|
||||
MySQL MySQLConfig `mapstructure:"mysql"`
|
||||
Logging LoggingConfig `mapstructure:"logging"`
|
||||
Admin AdminConfig `mapstructure:"admin"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `mapstructure:"port"`
|
||||
Mode string `mapstructure:"mode"`
|
||||
}
|
||||
|
||||
type MySQLConfig struct {
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
User string `mapstructure:"user"`
|
||||
Password string `mapstructure:"password"`
|
||||
Database string `mapstructure:"database"`
|
||||
|
||||
// 连接与字符集参数。
|
||||
Charset string `mapstructure:"charset"`
|
||||
ParseTime string `mapstructure:"parse_time"`
|
||||
Loc string `mapstructure:"loc"`
|
||||
|
||||
// 连接池参数。
|
||||
MaxIdleConns int `mapstructure:"max_idle_conns"`
|
||||
MaxOpenConns int `mapstructure:"max_open_conns"`
|
||||
ConnMaxLifetime int `mapstructure:"conn_max_lifetime"` // 单位:秒
|
||||
}
|
||||
|
||||
// DSN 根据各独立字段拼装 MySQL 连接串。
|
||||
// 优先级:显式字段 < 环境变量;缺省项使用合理默认值。
|
||||
func (d MySQLConfig) DSN() string {
|
||||
charset := d.Charset
|
||||
if charset == "" {
|
||||
charset = "utf8mb4"
|
||||
}
|
||||
parseTime := d.ParseTime
|
||||
if parseTime == "" {
|
||||
parseTime = "True"
|
||||
}
|
||||
loc := d.Loc
|
||||
if loc == "" {
|
||||
loc = "Local"
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%s&loc=%s",
|
||||
d.User, d.Password, d.Host, d.Port, d.Database, charset, parseTime, loc,
|
||||
)
|
||||
}
|
||||
|
||||
type LoggingConfig struct {
|
||||
Level string `mapstructure:"level"`
|
||||
Format string `mapstructure:"format"`
|
||||
}
|
||||
|
||||
// AdminConfig 后台管理相关配置。
|
||||
type AdminConfig struct {
|
||||
JWTSecret string `mapstructure:"jwt_secret"`
|
||||
TokenTTL string `mapstructure:"token_ttl"`
|
||||
}
|
||||
|
||||
// Load 从 configPath 加载配置(为空则默认 configs/config.yaml)。
|
||||
// 配置文件中使用 ${ENV} 占位符的字段会被对应环境变量替换,
|
||||
// 敏感信息(dsn/secret/token)据此注入,禁止硬编码。
|
||||
func Load(configPath string) (*Config, error) {
|
||||
if configPath == "" {
|
||||
configPath = "configs/config.yaml"
|
||||
}
|
||||
raw, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read config %s: %w", configPath, err)
|
||||
}
|
||||
// 先展开 ${ENV} 占位符,再交给 viper 解析。
|
||||
expanded := os.ExpandEnv(string(raw))
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigType("yaml")
|
||||
if err := v.ReadConfig(strings.NewReader(expanded)); err != nil {
|
||||
return nil, fmt.Errorf("parse config: %w", err)
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal config: %w", err)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
Reference in New Issue
Block a user