Bladeren bron

refactor: gofmt -l -w -s package

runningwater 8 maanden geleden
bovenliggende
commit
6b5c735acf

+ 3 - 4
app/http/controllers/api/v1/auth/signup_controller.go

@@ -13,7 +13,7 @@ type SignupController struct {
 }
 
 func (controller *SignupController) IsPhoneExist(c *gin.Context) {
-	
+
 	// 初始化请求对象
 	req := requests.SignupPhoneExistRequest{}
 	if ok := requests.Validate(c, &req, requests.ValidateSignupPhoneExist); !ok {
@@ -26,12 +26,11 @@ func (controller *SignupController) IsPhoneExist(c *gin.Context) {
 	})
 }
 
-
 func (controller *SignupController) IsEmailExist(c *gin.Context) {
 
 	// 初始化请求对象
 	req := requests.SignupEmailExistRequest{}
-	if ok := requests.Validate(c, &req, requests.ValidateSignupEmailExist);!ok {
+	if ok := requests.Validate(c, &req, requests.ValidateSignupEmailExist); !ok {
 		return
 	}
 
@@ -39,4 +38,4 @@ func (controller *SignupController) IsEmailExist(c *gin.Context) {
 	c.JSON(200, gin.H{
 		"exist": user.IsEmailExist(req.Email),
 	})
-}
+}

+ 1 - 1
app/http/controllers/api/v1/base_api_controller.go

@@ -3,4 +3,4 @@ package v1
 
 // BaseApiController 基础 API 控制器
 type BaseApiController struct {
-}
+}

+ 6 - 7
app/http/middlewares/logger.go

@@ -22,7 +22,6 @@ func (r responseBodyWriter) Write(b []byte) (int, error) {
 	return r.ResponseWriter.Write(b)
 }
 
-
 // Logger 记录请求日志
 func Logger() gin.HandlerFunc {
 	return func(c *gin.Context) {
@@ -55,7 +54,7 @@ func Logger() gin.HandlerFunc {
 			zap.String("ip", c.ClientIP()),
 			zap.String("user-agent", c.Request.UserAgent()),
 			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
-			zap.String("time", helpers.MicrosecondsStr(cost)),	
+			zap.String("time", helpers.MicrosecondsStr(cost)),
 		}
 
 		// Body 内容
@@ -64,13 +63,13 @@ func Logger() gin.HandlerFunc {
 			logFields = append(logFields, zap.String("ResponseBody", w.body.String()))
 		}
 
-		if responStatus > 400 && responStatus < 500  {
+		if responStatus > 400 && responStatus < 500 {
 			// 403 404 等客户端错误,使用 Warn 级别
-			logger.Warn("HTTP Warning "+ cast.ToString(responStatus), logFields...)
-		} else if responStatus >= 500 && responStatus < 600  {
-			logger.Error("HTTP Error "+ cast.ToString(responStatus), logFields...)
+			logger.Warn("HTTP Warning "+cast.ToString(responStatus), logFields...)
+		} else if responStatus >= 500 && responStatus < 600 {
+			logger.Error("HTTP Error "+cast.ToString(responStatus), logFields...)
 		} else {
 			logger.Debug("HTTP Access Log", logFields...)
 		}
 	}
-}
+}

+ 5 - 5
app/http/middlewares/recovery.go

@@ -19,7 +19,7 @@ func Recovery() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		defer func() {
 			if err := recover(); err != nil {
-				
+
 				// 获取用户的请求信息
 				httpRquest, _ := httputil.DumpRequest(c.Request, true)
 
@@ -47,10 +47,10 @@ func Recovery() gin.HandlerFunc {
 				}
 				// 如果不是链接中断的情况,记录堆栈信息
 				logger.Error("[Recovery from panic]",
-					zap.Time("time", time.Now()), // 记录当前时间
-					zap.Any("error", err), // 记录错误信息
+					zap.Time("time", time.Now()),              // 记录当前时间
+					zap.Any("error", err),                     // 记录错误信息
 					zap.String("request", string(httpRquest)), // 记录请求信息
-					zap.Stack("stack"), // 记录堆栈信息
+					zap.Stack("stack"),                        // 记录堆栈信息
 				)
 				c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
 					"message": "服务器内部错误,请稍后再试",
@@ -61,4 +61,4 @@ func Recovery() gin.HandlerFunc {
 		// 继续处理请求
 		c.Next()
 	}
-}
+}

+ 4 - 4
app/models/model.go

@@ -4,10 +4,10 @@ import "time"
 
 // BaseModel 基础模型
 type BaseModel struct {
-	ID        uint           `gorm:"column:id;primaryKey;autoIncrement;" json:"id,omitempty"` // 主键ID
+	ID uint `gorm:"column:id;primaryKey;autoIncrement;" json:"id,omitempty"` // 主键ID
 }
 
 type CommonTimestampsField struct {
-	CreatedAt  time.Time `gorm:"column:created_at;index;" json:"created_at,omitempty"`   // 创建时间
-	UpdatedAt  time.Time `gorm:"column:updated_at;index;" json:"updated_at,omitempty"`   // 更新时间
-}
+	CreatedAt time.Time `gorm:"column:created_at;index;" json:"created_at,omitempty"` // 创建时间
+	UpdatedAt time.Time `gorm:"column:updated_at;index;" json:"updated_at,omitempty"` // 更新时间
+}

+ 7 - 7
app/models/user/user_model.go

@@ -5,12 +5,12 @@ import "github.com/runningwater/gohub/app/models"
 
 // User 用户模型
 type User struct {
-    models.BaseModel
+	models.BaseModel
 
-    Name     string `json:"name,omitempty"`
-    Email    string `json:"-"`
-    Phone    string `json:"-"`
-    Password string `json:"-"`
+	Name     string `json:"name,omitempty"`
+	Email    string `json:"-"`
+	Phone    string `json:"-"`
+	Password string `json:"-"`
 
-    models.CommonTimestampsField
-}
+	models.CommonTimestampsField
+}

+ 1 - 2
app/models/user/user_util.go

@@ -2,7 +2,6 @@ package user
 
 import "github.com/runningwater/gohub/pkg/database"
 
-
 func IsEmailExist(email string) bool {
 	var count int64
 	database.DB.Model(&User{}).Where("email = ?", email).Count(&count)
@@ -13,4 +12,4 @@ func IsPhoneExist(phone string) bool {
 	var count int64
 	database.DB.Model(&User{}).Where("phone = ?", phone).Count(&count)
 	return count > 0
-}
+}

+ 12 - 11
app/requests/requests.go

@@ -20,16 +20,17 @@ type ValidatorFunc func(any, *gin.Context) map[string][]string
 // handler: 自定义验证函数
 // 返回值是一个布尔值,表示验证是否成功  如果验证失败,返回错误信息,否则返回空映射
 // 调用示例:
-// if ok := requests.Validate(c, &requests.SignupRequest{}, requests.Signup); !ok {
-//       return
-// }
+//
+//	if ok := requests.Validate(c, &requests.SignupRequest{}, requests.Signup); !ok {
+//	      return
+//	}
 func Validate(c *gin.Context, obj any, handler ValidatorFunc) bool {
 
 	// 1. 解析请求, 支持 JSON 数据、表单请求和 URL Query 参数
 	if err := c.ShouldBind(obj); err != nil {
 		c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
 			"message": "请求解析错误,请确认请求格式是否正确。上传文件请使用 multipart 标头, 参数请使用 JSON 格式",
-			"error": err.Error(),
+			"error":   err.Error(),
 		})
 		return false
 	}
@@ -41,7 +42,7 @@ func Validate(c *gin.Context, obj any, handler ValidatorFunc) bool {
 	if len(errs) > 0 {
 		c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
 			"message": "请求验证不通过,具体请查看 errors",
-			"errors": errs,
+			"errors":  errs,
 		})
 		return false
 	}
@@ -56,13 +57,13 @@ func Validate(c *gin.Context, obj any, handler ValidatorFunc) bool {
 // messages: 自定义错误信息
 // 返回值是一个映射,包含字段名和对应的错误信息
 func validate(data any, rules, messages govalidator.MapData) map[string][]string {
-	
+
 	opts := govalidator.Options{
-		Data:         data,
-		Rules:        rules,
+		Data:          data,
+		Rules:         rules,
 		TagIdentifier: "valid", // 使用结构体中的valid标签
-		Messages:     messages,
-	}	
+		Messages:      messages,
+	}
 
 	return govalidator.New(opts).ValidateStruct()
-}
+}

+ 16 - 17
app/requests/signup_request.go

@@ -15,23 +15,22 @@ type SignupEmailExistRequest struct {
 
 func ValidateSignupPhoneExist(data any, c *gin.Context) map[string][]string {
 
-		// 自定义验证规则
-		rules := govalidator.MapData{
-			"phone": []string{"required", "digits:11"},
-		}
-
-		// 自定义错误信息
-		messages := govalidator.MapData{
-			"phone": []string{
-				"required:手机号不能为空",
-				"digits:手机号必须是11位数字",
-			},
-		}
-
-		// 执行验证
-		return validate(data, rules, messages)
-}
+	// 自定义验证规则
+	rules := govalidator.MapData{
+		"phone": []string{"required", "digits:11"},
+	}
 
+	// 自定义错误信息
+	messages := govalidator.MapData{
+		"phone": []string{
+			"required:手机号不能为空",
+			"digits:手机号必须是11位数字",
+		},
+	}
+
+	// 执行验证
+	return validate(data, rules, messages)
+}
 
 func ValidateSignupEmailExist(data any, c *gin.Context) map[string][]string {
 
@@ -51,4 +50,4 @@ func ValidateSignupEmailExist(data any, c *gin.Context) map[string][]string {
 	}
 	// 执行验证
 	return validate(data, rules, messages)
-}
+}

+ 3 - 3
bootstrap/database.go

@@ -34,7 +34,7 @@ func SetupDB() {
 	case "sqlite":
 		// 初始化 SQLite 数据库
 		database := config.GetString("database.sqlite.database")
-		dbConfig =  sqlite.Open(database)
+		dbConfig = sqlite.Open(database)
 	default:
 		panic(errors.New("不支持的数据库连接"))
 	}
@@ -46,7 +46,7 @@ func SetupDB() {
 	// 设置最大空闲连接数
 	database.SQLDB.SetMaxIdleConns(config.GetInt("database.mysql.max_idle_connections"))
 	// 设置连接的最大存活时间
-	database.SQLDB.SetConnMaxLifetime(time.Duration(config.GetInt("database.mysql.max_life_seconds"))* time.Second)
+	database.SQLDB.SetConnMaxLifetime(time.Duration(config.GetInt("database.mysql.max_life_seconds")) * time.Second)
 
 	_ = database.DB.AutoMigrate(&user.User{})
-}
+}

+ 1 - 1
bootstrap/logger.go

@@ -19,4 +19,4 @@ func SetupLogger() {
 		config.GetString("log.type"),
 		config.GetString("log.level"),
 	)
-}
+}

+ 2 - 4
bootstrap/route.go

@@ -29,18 +29,16 @@ func setup404Handler(router *gin.Engine) {
 		} else {
 			// 默认返回 JSON
 			c.JSON(http.StatusNotFound, gin.H{
-				"error_code": 404,
+				"error_code":    404,
 				"error_message": "404 Not Found",
 			})
 		}
 	})
 }
 
-
-
 func registerGlobalMiddleWare(router *gin.Engine) {
 	router.Use(
 		middlewares.Logger(),
 		middlewares.Recovery(),
 	)
-}
+}

+ 19 - 20
config/app.go

@@ -3,31 +3,30 @@ package config
 
 import "github.com/runningwater/gohub/pkg/config"
 
-
 func init() {
-    config.Add("app", func() map[string] any {
-        return map[string]any{
+	config.Add("app", func() map[string]any {
+		return map[string]any{
 
-            // 应用名称
-            "name": config.Env("APP_NAME", "Gohub"),
+			// 应用名称
+			"name": config.Env("APP_NAME", "Gohub"),
 
-            // 当前环境,用以区分多环境,一般为 local, stage, production, test
-            "env": config.Env("APP_ENV", "production"),
+			// 当前环境,用以区分多环境,一般为 local, stage, production, test
+			"env": config.Env("APP_ENV", "production"),
 
-            // 是否进入调试模式
-            "debug": config.Env("APP_DEBUG", false),
+			// 是否进入调试模式
+			"debug": config.Env("APP_DEBUG", false),
 
-            // 应用服务端口
-            "port": config.Env("APP_PORT", "3000"),
+			// 应用服务端口
+			"port": config.Env("APP_PORT", "3000"),
 
-            // 加密会话、JWT 加密
-            "key": config.Env("APP_KEY", "33446a9dcf9ea060a0a6532b166da32f304af0de"),
+			// 加密会话、JWT 加密
+			"key": config.Env("APP_KEY", "33446a9dcf9ea060a0a6532b166da32f304af0de"),
 
-            // 用以生成链接
-            "url": config.Env("APP_URL", "http://localhost:3000"),
+			// 用以生成链接
+			"url": config.Env("APP_URL", "http://localhost:3000"),
 
-            // 设置时区,JWT 里会使用,日志记录里也会使用到
-            "timezone": config.Env("TIMEZONE", "Asia/Shanghai"),
-        }
-    })
-}
+			// 设置时区,JWT 里会使用,日志记录里也会使用到
+			"timezone": config.Env("TIMEZONE", "Asia/Shanghai"),
+		}
+	})
+}

+ 1 - 1
config/config.go

@@ -3,4 +3,4 @@ package config
 
 // Initialize 触发加载 config 包的所有 init 函数
 func Initialize() {
-}
+}

+ 4 - 4
config/database.go

@@ -10,12 +10,12 @@ func init() {
 			// MySQL 配置
 			"mysql": map[string]any{
 				// 数据库连接信息,可以使用 DSN 格式
-				"host": config.Env("DB_HOST", "127.0.0.1"),
-				"port": config.Env("DB_PORT", "3306"),
+				"host":     config.Env("DB_HOST", "127.0.0.1"),
+				"port":     config.Env("DB_PORT", "3306"),
 				"database": config.Env("DB_DATABASE", "gohub"),
 				"username": config.Env("DB_USERNAME", "root"),
 				"password": config.Env("DB_PASSWORD", ""),
-				"charset": "utf8mb4",
+				"charset":  "utf8mb4",
 				// 数据库连接池配置
 				"max_idle_connections": config.Env("DB_MAX_IDLE_CONNECTIONS", 100),
 				"max_open_connections": config.Env("DB_MAX_OPEN_CONNECTIONS", 25),
@@ -29,4 +29,4 @@ func init() {
 			},
 		}
 	})
-}
+}

+ 7 - 7
config/log.go

@@ -5,7 +5,7 @@ import "github.com/runningwater/gohub/pkg/config"
 func init() {
 	config.Add("log", func() map[string]any {
 		return map[string]any{
-			
+
 			// 日志级别,必须是以下这些选项:debug, info, warn, error
 			"level": config.Env("LOG_LEVEL", "debug"),
 			// 日志类型,必须是以下这些选项:
@@ -13,11 +13,11 @@ func init() {
 			// daily 每天一个文件
 			"type": config.Env("LOG_TYPE", "single"),
 			// 滚动日志配置
-			"filename": config.Env("LOG_NAME", "storage/logs/logs.log"),
-			"max_size": config.Env("LOG_MAX_SIZE", 64), // MB
-			"max_backups": config.Env("LOG_MAX_BACKUPS", 5), // 保留的最大备份数
-			"max_age": config.Env("LOG_MAX_AGE", 7), // 保留的最大天数, 单位:天 0表示不限制
-			"compress": config.Env("LOG_COMPRESS", false), // 是否压缩
+			"filename":    config.Env("LOG_NAME", "storage/logs/logs.log"),
+			"max_size":    config.Env("LOG_MAX_SIZE", 64),    // MB
+			"max_backups": config.Env("LOG_MAX_BACKUPS", 5),  // 保留的最大备份数
+			"max_age":     config.Env("LOG_MAX_AGE", 7),      // 保留的最大天数, 单位:天 0表示不限制
+			"compress":    config.Env("LOG_COMPRESS", false), // 是否压缩
 		}
 	})
-}
+}

+ 3 - 0
go.mod

@@ -4,6 +4,7 @@ go 1.24.2
 
 require (
 	github.com/gin-gonic/gin v1.10.0
+	github.com/go-redis/redis v6.15.9+incompatible
 	github.com/spf13/cast v1.7.1
 	github.com/spf13/viper v1.20.1
 	github.com/thedevsaddam/govalidator v1.9.10
@@ -37,6 +38,8 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.22 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/onsi/ginkgo v1.16.5 // indirect
+	github.com/onsi/gomega v1.18.1 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/sagikazarmark/locafero v0.7.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect

+ 93 - 0
go.sum

@@ -2,6 +2,9 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc
 github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
 github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@@ -11,6 +14,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
 github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
 github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
@@ -27,15 +32,34 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
 github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
+github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
 github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -61,6 +85,20 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
 github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -83,6 +121,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -97,6 +136,7 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
@@ -106,23 +146,76 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
 golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
 golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
 golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
 golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
 golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
 google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 60 - 60
pkg/config/config.go

@@ -21,119 +21,119 @@ var ConfigFuncs map[string]ConfigFunc
 
 func init() {
 
-    // 1. 初始化 Viper 库
-    viper = viperlib.New()
-    // 2. 配置类型,支持 "json", "toml", "yaml", "yml", "properties",
-    //             "props", "prop", "env", "dotenv"
-    viper.SetConfigType("env")
-    // 3. 环境变量配置文件查找的路径,相对于 main.go
-    viper.AddConfigPath(".")
-    // 4. 设置环境变量前缀,用以区分 Go 的系统环境变量
-    viper.SetEnvPrefix("appenv")
-    // 5. 读取环境变量(支持 flags)
-    viper.AutomaticEnv()
-
-    ConfigFuncs = make(map[string]ConfigFunc)
+	// 1. 初始化 Viper 库
+	viper = viperlib.New()
+	// 2. 配置类型,支持 "json", "toml", "yaml", "yml", "properties",
+	//             "props", "prop", "env", "dotenv"
+	viper.SetConfigType("env")
+	// 3. 环境变量配置文件查找的路径,相对于 main.go
+	viper.AddConfigPath(".")
+	// 4. 设置环境变量前缀,用以区分 Go 的系统环境变量
+	viper.SetEnvPrefix("appenv")
+	// 5. 读取环境变量(支持 flags)
+	viper.AutomaticEnv()
+
+	ConfigFuncs = make(map[string]ConfigFunc)
 }
 
 // InitConfig 初始化配置信息,完成对环境变量以及 config 信息的加载
 func InitConfig(env string) {
-    // 1. 加载环境变量
-    loadEnv(env)
-    // 2. 注册配置信息
-    loadConfig()
+	// 1. 加载环境变量
+	loadEnv(env)
+	// 2. 注册配置信息
+	loadConfig()
 }
 
 func loadConfig() {
-    for name, fn := range ConfigFuncs {
-        viper.Set(name, fn())
-    }
+	for name, fn := range ConfigFuncs {
+		viper.Set(name, fn())
+	}
 }
 
 func loadEnv(envSuffix string) {
 
-    // 默认加载 .env 文件,如果有传参 --env=name 的话,加载 .env.name 文件
-    envPath := ".env"
-    if len(envSuffix) > 0 {
-        filepath := ".env." + envSuffix
-        if _, err := os.Stat(filepath); err == nil {
-            // 如 .env.testing 或 .env.stage
-            envPath = filepath
-        }
-    }
-
-    // 加载 env
-    viper.SetConfigName(envPath)
-    if err := viper.ReadInConfig(); err != nil {
-        panic(err)
-    }
-
-    // 监控 .env 文件,变更时重新加载
-    viper.WatchConfig()
+	// 默认加载 .env 文件,如果有传参 --env=name 的话,加载 .env.name 文件
+	envPath := ".env"
+	if len(envSuffix) > 0 {
+		filepath := ".env." + envSuffix
+		if _, err := os.Stat(filepath); err == nil {
+			// 如 .env.testing 或 .env.stage
+			envPath = filepath
+		}
+	}
+
+	// 加载 env
+	viper.SetConfigName(envPath)
+	if err := viper.ReadInConfig(); err != nil {
+		panic(err)
+	}
+
+	// 监控 .env 文件,变更时重新加载
+	viper.WatchConfig()
 }
 
 // Env 读取环境变量,支持默认值
 func Env(envName string, defaultValue ...any) any {
-    if len(defaultValue) > 0 {
-        return internalGet(envName, defaultValue[0])
-    }
-    return internalGet(envName)
+	if len(defaultValue) > 0 {
+		return internalGet(envName, defaultValue[0])
+	}
+	return internalGet(envName)
 }
 
 // Add 新增配置项
 func Add(name string, configFn ConfigFunc) {
-    ConfigFuncs[name] = configFn
+	ConfigFuncs[name] = configFn
 }
 
 // Get 获取配置项
 // 第一个参数 path 允许使用点式获取,如:app.name
 // 第二个参数允许传参默认值
 func Get(path string, defaultValue ...any) string {
-    return GetString(path, defaultValue...)
+	return GetString(path, defaultValue...)
 }
 
 func internalGet(path string, defaultValue ...any) any {
-    // config 或者环境变量不存在的情况
-    if !viper.IsSet(path) || helpers.Empty(viper.Get(path)) {
-        if len(defaultValue) > 0 {
-            return defaultValue[0]
-        }
-        return nil
-    }
-    return viper.Get(path)
+	// config 或者环境变量不存在的情况
+	if !viper.IsSet(path) || helpers.Empty(viper.Get(path)) {
+		if len(defaultValue) > 0 {
+			return defaultValue[0]
+		}
+		return nil
+	}
+	return viper.Get(path)
 }
 
 // GetString 获取 String 类型的配置信息
 func GetString(path string, defaultValue ...any) string {
-    return cast.ToString(internalGet(path, defaultValue...))
+	return cast.ToString(internalGet(path, defaultValue...))
 }
 
 // GetInt 获取 Int 类型的配置信息
 func GetInt(path string, defaultValue ...any) int {
-    return cast.ToInt(internalGet(path, defaultValue...))
+	return cast.ToInt(internalGet(path, defaultValue...))
 }
 
 // GetFloat64 获取 float64 类型的配置信息
 func GetFloat64(path string, defaultValue ...any) float64 {
-    return cast.ToFloat64(internalGet(path, defaultValue...))
+	return cast.ToFloat64(internalGet(path, defaultValue...))
 }
 
 // GetInt64 获取 Int64 类型的配置信息
 func GetInt64(path string, defaultValue ...any) int64 {
-    return cast.ToInt64(internalGet(path, defaultValue...))
+	return cast.ToInt64(internalGet(path, defaultValue...))
 }
 
 // GetUint 获取 Uint 类型的配置信息
 func GetUint(path string, defaultValue ...any) uint {
-    return cast.ToUint(internalGet(path, defaultValue...))
+	return cast.ToUint(internalGet(path, defaultValue...))
 }
 
 // GetBool 获取 Bool 类型的配置信息
 func GetBool(path string, defaultValue ...any) bool {
-    return cast.ToBool(internalGet(path, defaultValue...))
+	return cast.ToBool(internalGet(path, defaultValue...))
 }
 
 // GetStringMapString 获取结构数据
 func GetStringMapString(path string) map[string]string {
-    return viper.GetStringMapString(path)
-}
+	return viper.GetStringMapString(path)
+}

+ 2 - 2
pkg/database/database.go

@@ -27,7 +27,7 @@ func Connect(dbConfig gorm.Dialector, _logger gormlgger.Interface) {
 	}
 	// 获取底层的 sql.DB 实例
 	SQLDB, err = DB.DB()
-	if err!= nil {
+	if err != nil {
 		fmt.Println("数据库连接失败", err.Error())
 	}
-}
+}

+ 23 - 23
pkg/helpers/helpers.go

@@ -9,31 +9,31 @@ import (
 
 // Empty 类似于 PHP 的 empty() 函数
 func Empty(val any) bool {
-    if val == nil {
-        return true
-    }
-    v := reflect.ValueOf(val)
-    switch v.Kind() {
-    case reflect.String, reflect.Array:
-        return v.Len() == 0
-    case reflect.Map, reflect.Slice:
-        return v.Len() == 0 || v.IsNil()
-    case reflect.Bool:
-        return !v.Bool()
-    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-        return v.Int() == 0
-    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-        return v.Uint() == 0
-    case reflect.Float32, reflect.Float64:
-        return v.Float() == 0
-    case reflect.Interface, reflect.Ptr:
-        return v.IsNil()
-    }
-    return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
+	if val == nil {
+		return true
+	}
+	v := reflect.ValueOf(val)
+	switch v.Kind() {
+	case reflect.String, reflect.Array:
+		return v.Len() == 0
+	case reflect.Map, reflect.Slice:
+		return v.Len() == 0 || v.IsNil()
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		return v.IsNil()
+	}
+	return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
 }
 
 // MicrosecondsStr 将 time.Duration 类型(nano seconds 为单位)
 // 输出为小数点后 3 位的 ms (microsecond 毫秒,千分之一秒)
 func MicrosecondsStr(elapsed time.Duration) string {
-    return fmt.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6)
-}
+	return fmt.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6)
+}

+ 11 - 8
pkg/logger/gorm_logger.go

@@ -16,7 +16,7 @@ import (
 
 // GormLogger 操作对象,实现 gormlogger.Interface 接口,用于自定义 GORM 的日志输出
 type GormLogger struct {
-	ZapLogger *zap.Logger
+	ZapLogger     *zap.Logger
 	SlowThreshold time.Duration
 }
 
@@ -29,8 +29,8 @@ type GormLogger struct {
 func NewGormLogger() GormLogger {
 
 	return GormLogger{
-		ZapLogger:     Logger, // 使用全局的 logger.Logger 对象
-		SlowThreshold: 200 * time.Millisecond,  // 慢查询阈值,200ms
+		ZapLogger:     Logger,                 // 使用全局的 logger.Logger 对象
+		SlowThreshold: 200 * time.Millisecond, // 慢查询阈值,200ms
 	}
 }
 
@@ -41,18 +41,22 @@ func (l GormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface {
 		SlowThreshold: l.SlowThreshold,
 	}
 }
+
 // Info 实现 gormlogger.Interface 接口的 Info 方法
 func (l GormLogger) Info(_ context.Context, str string, args ...any) {
 	l.logger().Sugar().Debugf(str, args...)
 }
+
 // Warn 实现 gormlogger.Interface 接口的 Warn 方法
 func (l GormLogger) Warn(_ context.Context, str string, args ...any) {
 	l.logger().Sugar().Warnf(str, args...)
 }
+
 // Error 实现 gormlogger.Interface 接口的 Error 方法
 func (l GormLogger) Error(_ context.Context, str string, args ...any) {
 	l.logger().Sugar().Errorf(str, args...)
 }
+
 // Trace 实现 gormlogger.Interface 接口的 Trace 方法
 func (l GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
 
@@ -89,13 +93,12 @@ func (l GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql s
 	l.logger().Debug("Database Query", logFields...)
 }
 
-
 // logger 内部方法,确保 Zap 内置信息 Caller 的准确性
 // 返回值: *zap.Logger 对象
 func (l GormLogger) logger() *zap.Logger {
 	var (
-		gormPackage    =  filepath.Join("gorm.io", "gorm")
-		zapGormPackage =  filepath.Join("moul.io", "zapgorm2")
+		gormPackage    = filepath.Join("gorm.io", "gorm")
+		zapGormPackage = filepath.Join("moul.io", "zapgorm2")
 	)
 
 	// 减去一次封装,以及一次在 logger 初始化中添加 zap.AddCallerSkip(1)
@@ -109,9 +112,9 @@ func (l GormLogger) logger() *zap.Logger {
 		case strings.Contains(file, gormPackage):
 		case strings.Contains(file, zapGormPackage):
 		default:
-			// 返回一个附带跳过行号的 zap.Logger 
+			// 返回一个附带跳过行号的 zap.Logger
 			return clone.WithOptions(zap.AddCallerSkip(i))
 		}
 	}
 	return l.ZapLogger
-}
+}

+ 50 - 43
pkg/logger/logger.go

@@ -31,10 +31,10 @@ func Init(filename string, maxSize, maxBackup, maxAge int, compress bool, logTyp
 	core := zapcore.NewCore(getEncoder(), writeSyncer, logLevel)
 	// 初始化 logger
 	Logger = zap.New(core,
-		 zap.AddCaller(), // 调用文件和行号,内部使用 runtime.Caller
-		 zap.AddCallerSkip(1), // 调用文件和行号,内部使用 runtime.Caller
-		 //zap.Development(), // 开发模式,堆栈跟踪
-		 zap.AddStacktrace(zapcore.ErrorLevel), // 记录错误级别以上的堆栈信息
+		zap.AddCaller(),      // 调用文件和行号,内部使用 runtime.Caller
+		zap.AddCallerSkip(1), // 调用文件和行号,内部使用 runtime.Caller
+		//zap.Development(), // 开发模式,堆栈跟踪
+		zap.AddStacktrace(zapcore.ErrorLevel), // 记录错误级别以上的堆栈信息
 	)
 
 	// 设置全局 logger
@@ -46,18 +46,18 @@ func Init(filename string, maxSize, maxBackup, maxAge int, compress bool, logTyp
 func getEncoder() zapcore.Encoder {
 	// 日志模式规则
 	encoderConfig := zapcore.EncoderConfig{
-		TimeKey:        "time", // 时间字段名
-		LevelKey:       "level", // 日志级别字段名
-		NameKey:        "logger", // 日志名称字段名
-		CallerKey:      "caller", // 调用者字段名
-		FunctionKey:    zapcore.OmitKey, // 函数名字段名,不显示
-		MessageKey:     "msg", // 消息字段名
-		StacktraceKey:  "stacktrace", // 堆栈跟踪字段名
-		LineEnding:     zapcore.DefaultLineEnding, // 每行日志的结尾添加换行符
-		EncodeLevel:    zapcore.CapitalLevelEncoder, // 大写编码器
-		EncodeTime:     customTimeEncoder, // 自定义时间编码器
+		TimeKey:        "time",                         // 时间字段名
+		LevelKey:       "level",                        // 日志级别字段名
+		NameKey:        "logger",                       // 日志名称字段名
+		CallerKey:      "caller",                       // 调用者字段名
+		FunctionKey:    zapcore.OmitKey,                // 函数名字段名,不显示
+		MessageKey:     "msg",                          // 消息字段名
+		StacktraceKey:  "stacktrace",                   // 堆栈跟踪字段名
+		LineEnding:     zapcore.DefaultLineEnding,      // 每行日志的结尾添加换行符
+		EncodeLevel:    zapcore.CapitalLevelEncoder,    // 大写编码器
+		EncodeTime:     customTimeEncoder,              // 自定义时间编码器
 		EncodeDuration: zapcore.SecondsDurationEncoder, // 以秒为单位显示持续时间
-		EncodeCaller:   zapcore.ShortCallerEncoder, // 短路径编码器
+		EncodeCaller:   zapcore.ShortCallerEncoder,     // 短路径编码器
 	}
 
 	if app.IsLocal() {
@@ -86,15 +86,15 @@ func getLogWriter(filename string, maxSize, maxBackup, maxAge int, compress bool
 
 	// 滚动日志,详见 config/log.go
 	lumberJackLogger := &lumberjack.Logger{
-		Filename:   filename, // 日志文件名
-		MaxSize:    maxSize, // 每个日志文件保存的最大尺寸 单位:MB
+		Filename:   filename,  // 日志文件名
+		MaxSize:    maxSize,   // 每个日志文件保存的最大尺寸 单位:MB
 		MaxBackups: maxBackup, // 日志文件最多保存多少个备份
-		MaxAge:     maxAge, // 文件最多保存多少天
-		Compress:   compress, // 是否压缩
-	}	
+		MaxAge:     maxAge,    // 文件最多保存多少天
+		Compress:   compress,  // 是否压缩
+	}
 	if app.IsLocal() {
 		// 如果是本地环境,使用标准输出和文件输出
-		return  zapcore.NewMultiWriteSyncer(
+		return zapcore.NewMultiWriteSyncer(
 			zapcore.AddSync(os.Stdout),
 			zapcore.AddSync(lumberJackLogger),
 		)
@@ -106,15 +106,16 @@ func getLogWriter(filename string, maxSize, maxBackup, maxAge int, compress bool
 
 // Dump 调试专用, 不会中断程序,会在终端打印 warning 信息。
 // 第一个参数会使用 json.Marshal 进行渲染,第二个参数可选
-//    logger.Dump(user.User{Name: "test"})
-//    logger.Dump(user.User{Name: "test"}, "用户信息")
+//
+//	logger.Dump(user.User{Name: "test"})
+//	logger.Dump(user.User{Name: "test"}, "用户信息")
 func Dump(v any, msg ...string) {
 	valueStr := jsonString(v)
 	if len(msg) > 0 {
 		Logger.Warn("Dump", zap.String(msg[0], valueStr))
 	} else {
 		Logger.Warn("Dump", zap.String("data", valueStr))
-	}	
+	}
 }
 
 // LogIf 当 err != nill 时记录 error 等级的日志
@@ -139,76 +140,82 @@ func LogInfoIf(err error) {
 }
 
 // Debug 调试专用, 不会中断程序
-//  logger.Debug("Database", zap.String("sql", sql))
+//
+//	logger.Debug("Database", zap.String("sql", sql))
 func Debug(msg string, fields ...zap.Field) {
 	Logger.Debug(msg, fields...)
 }
 
 // Info 信息级别
-func Info(msg string, fields...zap.Field) {
+func Info(msg string, fields ...zap.Field) {
 	Logger.Info(msg, fields...)
 }
+
 // Warn 警告级别
-func Warn(msg string, fields...zap.Field) {
+func Warn(msg string, fields ...zap.Field) {
 	Logger.Warn(msg, fields...)
 }
+
 // Error 错误级别
-func Error(msg string, fields...zap.Field) {
+func Error(msg string, fields ...zap.Field) {
 	Logger.Error(msg, fields...)
 }
+
 // Fatal 致命级别
-func Fatal(msg string, fields...zap.Field) {
+func Fatal(msg string, fields ...zap.Field) {
 	Logger.Fatal(msg, fields...)
 }
+
 // DebugString 记录一条字符串类型的 debug 日志
-//   logger.DebugString("User", "name", "John")
+//
+//	logger.DebugString("User", "name", "John")
 func DebugString(modeleName, name, msg string) {
 	Logger.Debug(modeleName, zap.String(name, msg))
 }
 
-
 func InfoString(moduleName, name, msg string) {
-    Logger.Info(moduleName, zap.String(name, msg))
+	Logger.Info(moduleName, zap.String(name, msg))
 }
 
 func WarnString(moduleName, name, msg string) {
-    Logger.Warn(moduleName, zap.String(name, msg))
+	Logger.Warn(moduleName, zap.String(name, msg))
 }
 
 func ErrorString(moduleName, name, msg string) {
-    Logger.Error(moduleName, zap.String(name, msg))
+	Logger.Error(moduleName, zap.String(name, msg))
 }
 
 func FatalString(moduleName, name, msg string) {
-    Logger.Fatal(moduleName, zap.String(name, msg))
+	Logger.Fatal(moduleName, zap.String(name, msg))
 }
 
 // DebugJSON 记录对象类型的 debug 日志,使用 json.Marshal 进行编码。调用示例:
-//         logger.DebugJSON("Auth", "读取登录用户", auth.CurrentUser())
+//
+//	logger.DebugJSON("Auth", "读取登录用户", auth.CurrentUser())
 func DebugJSON(moduleName, name string, value any) {
-    Logger.Debug(moduleName, zap.String(name, jsonString(value)))
+	Logger.Debug(moduleName, zap.String(name, jsonString(value)))
 }
 
 func InfoJSON(moduleName, name string, value any) {
-    Logger.Info(moduleName, zap.String(name, jsonString(value)))
+	Logger.Info(moduleName, zap.String(name, jsonString(value)))
 }
 
 func WarnJSON(moduleName, name string, value any) {
-    Logger.Warn(moduleName, zap.String(name, jsonString(value)))
+	Logger.Warn(moduleName, zap.String(name, jsonString(value)))
 }
 
 func ErrorJSON(moduleName, name string, value any) {
-    Logger.Error(moduleName, zap.String(name, jsonString(value)))
+	Logger.Error(moduleName, zap.String(name, jsonString(value)))
 }
 
 func FatalJSON(moduleName, name string, value any) {
-    Logger.Fatal(moduleName, zap.String(name, jsonString(value)))
+	Logger.Fatal(moduleName, zap.String(name, jsonString(value)))
 }
 
 func jsonString(v any) string {
-	b,err := json.Marshal(v)
+	b, err := json.Marshal(v)
 	if err != nil {
 		Logger.Error("Logger", zap.String("json.Marshal error", err.Error()))
 	}
 	return string(b)
-}
+}

+ 1 - 1
routes/api.go

@@ -20,4 +20,4 @@ func RegisterAPIRoutes(router *gin.Engine) {
 			authGroup.POST("/signup/email/exist", suc.IsEmailExist)
 		}
 	}
-}
+}