feat(*): go 后端项目脚手架

This commit is contained in:
2025-11-15 18:20:30 +08:00
commit 5bb025c1aa
39 changed files with 2459 additions and 0 deletions

130
pkg/config/config.go Normal file
View File

@@ -0,0 +1,130 @@
package config
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"sync"
"github.com/go-yaml/yaml"
"github.com/spf13/viper"
"github.com/zhilv666/navsite/pkg/consts"
)
var (
globalViper *viper.Viper
globalViperOnce sync.Once
configMu sync.RWMutex
cachedConfig *Config
)
// NewConfig 初始化配置
func NewConfig() *Config {
globalViperOnce.Do(func() {
globalViper = viper.New()
})
configPath := loadConfigFile()
if configPath == "" {
log.Println("⚠️ 未找到配置文件,使用默认配置并导出为 config.yaml")
cachedConfig = DefaultConfig()
exportConfig(cachedConfig, "yaml")
return cachedConfig
}
conf, err := parseConfig()
if err != nil {
log.Printf("⚠️ 解析配置失败,使用默认配置并导出为 config.yaml: %v", err)
conf = DefaultConfig()
exportConfig(conf, "yaml")
}
cachedConfig = conf
return conf
}
// loadConfigFile 加载配置文件
func loadConfigFile() string {
files := []string{
fmt.Sprintf("%s.yaml", consts.ConfigName),
fmt.Sprintf("%s.yml", consts.ConfigName),
fmt.Sprintf("%s.json", consts.ConfigName),
}
for _, file := range files {
if _, err := os.Stat(file); err == nil {
ext := filepath.Ext(file)[1:]
globalViper.SetConfigFile(file)
globalViper.SetConfigType(ext)
globalViper.AddConfigPath(".")
if err := globalViper.ReadInConfig(); err != nil {
log.Printf("⚠️ 读取配置文件 %s 失败: %v", file, err)
continue
}
log.Printf("✅ 成功加载配置文件: %s", file)
return file
}
}
return ""
}
// parseConfig 将配置解析为结构体
func parseConfig() (*Config, error) {
configMu.Lock()
defer configMu.Unlock()
var conf Config
if err := globalViper.Unmarshal(&conf); err != nil {
return nil, err
}
return &conf, nil
}
// exportConfig 导出配置文件(默认保存为 config.yaml
func exportConfig(conf *Config, format string) {
var (
data []byte
err error
)
switch format {
case "json":
data, err = json.MarshalIndent(conf, "", " ")
case "yaml", "yml", "":
format = "yaml"
data, err = yaml.Marshal(conf)
default:
log.Printf("⚠️ 不支持的导出格式: %s", format)
return
}
if err != nil {
log.Printf("⚠️ 导出 %s 格式配置失败: %v", format, err)
return
}
filename := fmt.Sprintf("%s.%s", consts.ConfigName, format)
if err := os.WriteFile(filename, data, 0644); err != nil {
log.Printf("⚠️ 写入配置文件 %s 失败: %v", filename, err)
} else {
log.Printf("✅ 已导出配置文件: %s", filename)
}
log.Printf("📋 当前 %s 配置:\n%s", format, data)
}
// GetConfig 获取当前配置(线程安全)
func GetConfig() *Config {
configMu.RLock()
defer configMu.RUnlock()
if cachedConfig == nil {
return DefaultConfig()
}
conf := *cachedConfig
return &conf
}