调整工厂模式的方法

This commit is contained in:
2025-12-05 00:07:15 +08:00
parent 0650feb0d2
commit 6146178111
15 changed files with 635 additions and 1039 deletions

View File

@@ -4,11 +4,13 @@ import (
"context"
"fmt"
"io"
"net/http"
"time"
"git.toowon.com/jimmy/go-common/config"
"git.toowon.com/jimmy/go-common/email"
"git.toowon.com/jimmy/go-common/logger"
"git.toowon.com/jimmy/go-common/middleware"
"git.toowon.com/jimmy/go-common/sms"
"git.toowon.com/jimmy/go-common/storage"
"github.com/redis/go-redis/v9"
@@ -18,6 +20,41 @@ import (
"gorm.io/gorm"
)
// Factory 工厂类 - 黑盒模式设计
//
// 核心理念:
//
// 外部项目只需传递一个配置文件路径,即可直接使用所有功能,
// 无需关心内部实现细节。
//
// 推荐使用的黑盒方法:
// - GetMiddlewareChain():获取配置好的中间件链
// - LogInfo(), LogError():记录日志
// - RedisSet(), RedisGet()操作Redis
// - SendEmail(), SendSMS():发送邮件和短信
// - UploadFile(), GetFileURL():文件上传和访问
//
// 需要获取客户端对象的场景(高级功能):
// - GetDatabase()数据库操作GORM已经是很好的抽象
// - GetRedisClient()Redis高级操作Hash, List, Set, ZSet等
// - GetLogger()Logger高级功能Close等
//
// 使用示例:
//
// // 1. 创建工厂(传入配置文件路径)
// fac, _ := factory.NewFactoryFromFile("config.json")
//
// // 2. 直接使用黑盒方法(推荐)
// fac.LogInfo("用户登录成功")
// fac.RedisSet(ctx, "session:123", "data", time.Hour)
// fac.SendEmail([]string{"user@example.com"}, "主题", "内容")
// chain := fac.GetMiddlewareChain()
// chain.Append(yourAuthMiddleware) // 添加自定义中间件
//
// // 3. 获取客户端对象(仅在需要高级功能时)
// db, _ := fac.GetDatabase()
// db.Find(&users)
//
// Factory 工厂类,用于从配置创建各种客户端对象
type Factory struct {
cfg *config.Config
@@ -65,7 +102,8 @@ func (f *Factory) getEmailClient() (*email.Email, error) {
return e, nil
}
// SendEmail 发送邮件(黑盒模式)
// SendEmail 发送邮件(黑盒模式,推荐使用
// 自动使用配置文件中的SMTP配置发送邮件
// to: 收件人列表
// subject: 邮件主题
// body: 邮件正文(纯文本)
@@ -108,7 +146,8 @@ func (f *Factory) getSMSClient() (*sms.SMS, error) {
return s, nil
}
// SendSMS 发送短信(黑盒模式)
// SendSMS 发送短信(黑盒模式,推荐使用
// 自动使用配置文件中的阿里云短信配置发送短信
// phoneNumbers: 手机号列表
// templateParam: 模板参数map或JSON字符串
// templateCode: 模板代码(可选,如果为空使用配置中的模板代码)
@@ -153,15 +192,31 @@ func (f *Factory) getLogger() (*logger.Logger, error) {
return l, nil
}
// GetLogger 获取日志记录器对象(已初始化
// 返回已初始化的日志记录器对象,可直接使用
// 注意:推荐使用 LogDebug、LogInfo、LogWarn、LogError 等方法直接记录日志
// 如果需要使用logger的高级功能如Close方法可以使用此方法获取logger对象
// GetLogger 获取日志记录器对象(不推荐直接使用
//
// ⚠️ 不推荐直接使用此方法,推荐使用黑盒方法:
// - LogDebug, LogInfo, LogWarn, LogError记录简单日志
// - LogDebugf, LogInfof, LogWarnf, LogErrorf记录带字段的日志
//
// 仅在以下高级场景时使用:
// - 需要调用 Close() 方法关闭logger
// - 需要使用logger的其他高级功能
//
// 示例(不推荐):
//
// logger, _ := factory.GetLogger()
// defer logger.Close()
//
// 示例(推荐):
//
// factory.LogInfo("用户登录成功")
// factory.LogErrorf(map[string]interface{}{"user_id": 123}, "登录失败")
func (f *Factory) GetLogger() (*logger.Logger, error) {
return f.getLogger()
}
// LogDebug 记录调试日志
// LogDebug 记录调试日志(黑盒模式,推荐使用)
// 自动使用配置文件中的logger配置
// message: 日志消息
// args: 格式化参数(可选)
func (f *Factory) LogDebug(message string, args ...interface{}) {
@@ -182,7 +237,8 @@ func (f *Factory) LogDebug(message string, args ...interface{}) {
}
}
// LogDebugf 记录调试日志(带字段)
// LogDebugf 记录调试日志(带字段,黑盒模式,推荐使用
// 自动使用配置文件中的logger配置
// fields: 日志字段
// message: 日志消息
// args: 格式化参数(可选)
@@ -200,7 +256,8 @@ func (f *Factory) LogDebugf(fields map[string]interface{}, message string, args
l.Debugf(fields, message, args...)
}
// LogInfo 记录信息日志
// LogInfo 记录信息日志(黑盒模式,推荐使用)
// 自动使用配置文件中的logger配置
// message: 日志消息
// args: 格式化参数(可选)
func (f *Factory) LogInfo(message string, args ...interface{}) {
@@ -221,7 +278,8 @@ func (f *Factory) LogInfo(message string, args ...interface{}) {
}
}
// LogInfof 记录信息日志(带字段)
// LogInfof 记录信息日志(带字段,黑盒模式,推荐使用
// 自动使用配置文件中的logger配置
// fields: 日志字段
// message: 日志消息
// args: 格式化参数(可选)
@@ -239,7 +297,8 @@ func (f *Factory) LogInfof(fields map[string]interface{}, message string, args .
l.Infof(fields, message, args...)
}
// LogWarn 记录警告日志
// LogWarn 记录警告日志(黑盒模式,推荐使用)
// 自动使用配置文件中的logger配置
// message: 日志消息
// args: 格式化参数(可选)
func (f *Factory) LogWarn(message string, args ...interface{}) {
@@ -260,7 +319,8 @@ func (f *Factory) LogWarn(message string, args ...interface{}) {
}
}
// LogWarnf 记录警告日志(带字段)
// LogWarnf 记录警告日志(带字段,黑盒模式,推荐使用
// 自动使用配置文件中的logger配置
// fields: 日志字段
// message: 日志消息
// args: 格式化参数(可选)
@@ -278,7 +338,8 @@ func (f *Factory) LogWarnf(fields map[string]interface{}, message string, args .
l.Warnf(fields, message, args...)
}
// LogError 记录错误日志
// LogError 记录错误日志(黑盒模式,推荐使用)
// 自动使用配置文件中的logger配置
// message: 日志消息
// args: 格式化参数(可选)
func (f *Factory) LogError(message string, args ...interface{}) {
@@ -299,7 +360,8 @@ func (f *Factory) LogError(message string, args ...interface{}) {
}
}
// LogErrorf 记录错误日志(带字段)
// LogErrorf 记录错误日志(带字段,黑盒模式,推荐使用
// 自动使用配置文件中的logger配置
// fields: 日志字段
// message: 日志消息
// args: 格式化参数(可选)
@@ -370,9 +432,20 @@ func (f *Factory) getDatabase() (*gorm.DB, error) {
return db, nil
}
// GetDatabase 获取数据库连接对象(已初始化
// GetDatabase 获取数据库连接对象(推荐使用
// 返回已初始化的GORM数据库对象可直接使用
// 注意数据库保持返回GORM对象因为GORM已经提供了很好的抽象
//
// 数据库操作保持使用 GORM 对象,因为:
// - 数据库操作非常复杂多样(查询、插入、更新、删除、事务等)
// - GORM 已经提供了很好的抽象和 API
// - 无需在 factory 中重复封装所有数据库方法
//
// 示例:
//
// db, _ := factory.GetDatabase()
// db.Find(&users)
// db.Create(&user)
// db.Transaction(func(tx *gorm.DB) error { ... })
func (f *Factory) GetDatabase() (*gorm.DB, error) {
return f.getDatabase()
}
@@ -438,15 +511,35 @@ func (f *Factory) getRedisClient() (*redis.Client, error) {
return client, nil
}
// GetRedisClient 获取Redis客户端对象已初始化
// 返回已初始化的Redis客户端对象,可直接使用
// 注意:推荐使用 RedisGet、RedisSet、RedisDelete 等方法直接操作Redis
// 如果需要使用Redis的高级功能如Hash、List、Set等可以使用此方法获取客户端对象
// GetRedisClient 获取Redis客户端对象高级功能时使用
// 返回已初始化的Redis客户端对象
//
// 推荐使用黑盒方法:
// - RedisGet, RedisSet, RedisDelete, RedisExists常用操作
//
// 仅在需要使用高级功能时获取客户端:
// - Hash 操作HSet, HGet, HGetAll 等)
// - List 操作LPush, RPush, LRange 等)
// - Set 操作SAdd, SMembers 等)
// - ZSet 操作ZAdd, ZRange 等)
// - 其他高级功能
//
// 示例(常用操作,推荐):
//
// factory.RedisSet(ctx, "key", "value", time.Hour)
// value, _ := factory.RedisGet(ctx, "key")
//
// 示例(高级功能):
//
// client, _ := factory.GetRedisClient()
// client.HSet(ctx, "user:1", "name", "Alice")
// client.LPush(ctx, "queue", "task1")
func (f *Factory) GetRedisClient() (*redis.Client, error) {
return f.getRedisClient()
}
// RedisGet 获取Redis值黑盒模式
// RedisGet 获取Redis值黑盒模式,推荐使用
// 自动使用配置文件中的Redis配置
// key: Redis键
func (f *Factory) RedisGet(ctx context.Context, key string) (string, error) {
client, err := f.getRedisClient()
@@ -465,7 +558,8 @@ func (f *Factory) RedisGet(ctx context.Context, key string) (string, error) {
return result, nil
}
// RedisSet 设置Redis值黑盒模式
// RedisSet 设置Redis值黑盒模式,推荐使用
// 自动使用配置文件中的Redis配置
// key: Redis键
// value: Redis值
// expiration: 过期时间可选0表示不过期
@@ -488,7 +582,8 @@ func (f *Factory) RedisSet(ctx context.Context, key string, value interface{}, e
return nil
}
// RedisDelete 删除Redis键黑盒模式
// RedisDelete 删除Redis键黑盒模式,推荐使用
// 自动使用配置文件中的Redis配置
// keys: Redis键列表
func (f *Factory) RedisDelete(ctx context.Context, keys ...string) error {
if len(keys) == 0 {
@@ -508,7 +603,8 @@ func (f *Factory) RedisDelete(ctx context.Context, keys ...string) error {
return nil
}
// RedisExists 检查Redis键是否存在黑盒模式
// RedisExists 检查Redis键是否存在黑盒模式,推荐使用
// 自动使用配置文件中的Redis配置
// key: Redis键
func (f *Factory) RedisExists(ctx context.Context, key string) (bool, error) {
client, err := f.getRedisClient()
@@ -556,7 +652,8 @@ func (f *Factory) getStorage() (storage.Storage, error) {
return s, nil
}
// UploadFile 上传文件
// UploadFile 上传文件(黑盒模式,推荐使用)
// 自动根据配置选择存储类型OSS 或 MinIO无需关心内部实现
// ctx: 上下文
// objectKey: 对象键(文件路径)
// reader: 文件内容
@@ -583,8 +680,9 @@ func (f *Factory) UploadFile(ctx context.Context, objectKey string, reader io.Re
return url, nil
}
// GetFileURL 获取文件访问URLShow方法
// objectKey: 对象键
// GetFileURL 获取文件访问URL黑盒模式,推荐使用
// 自动根据配置选择存储类型返回文件的访问URL
// objectKey: 对象键(文件路径)
// expires: 过期时间0表示永久有效
func (f *Factory) GetFileURL(objectKey string, expires int64) (string, error) {
s, err := f.getStorage()
@@ -594,3 +692,75 @@ func (f *Factory) GetFileURL(objectKey string, expires int64) (string, error) {
return s.GetURL(objectKey, expires)
}
// GetMiddlewareChain 获取配置好的中间件链(黑盒模式)
// 自动包含Recovery、Logging、RateLimit如果配置了、CORS如果配置了、Timezone
// 返回已配置好的中间件链,可以通过 Append() 方法添加自定义中间件
//
// 示例1直接使用
//
// chain := factory.GetMiddlewareChain()
// http.Handle("/api/users", chain.ThenFunc(handleUsers))
//
// 示例2添加自定义中间件
//
// chain := factory.GetMiddlewareChain()
// chain.Append(yourCustomMiddleware1, yourCustomMiddleware2)
// http.Handle("/api/users", chain.ThenFunc(handleUsers))
func (f *Factory) GetMiddlewareChain() *middleware.Chain {
var middlewares []func(http.Handler) http.Handler
// 1. Recovery 中间件必需防止panic导致服务崩溃
l, _ := f.getLogger() // 获取logger如果失败会使用默认logger
middlewares = append(middlewares, middleware.Recovery(&middleware.RecoveryConfig{
Logger: l,
}))
// 2. Logging 中间件(必需,记录所有请求)
middlewares = append(middlewares, middleware.Logging(&middleware.LoggingConfig{
Logger: l,
}))
// 3. RateLimit 中间件(如果配置了限流)
if f.cfg != nil && f.cfg.RateLimit != nil {
if f.cfg.RateLimit.Enable {
// 从配置创建限流中间件
limiter := middleware.NewTokenBucketLimiter(
f.cfg.RateLimit.Rate,
time.Duration(f.cfg.RateLimit.Period)*time.Second,
)
var keyFunc func(r *http.Request) string
if f.cfg.RateLimit.ByIP {
keyFunc = func(r *http.Request) string {
return middleware.GetClientIP(r)
}
} else if f.cfg.RateLimit.ByUserID {
keyFunc = func(r *http.Request) string {
return r.Header.Get("X-User-ID")
}
}
middlewares = append(middlewares, middleware.RateLimit(&middleware.RateLimitConfig{
Limiter: limiter,
KeyFunc: keyFunc,
}))
}
}
// 4. CORS 中间件(如果配置了)
if f.cfg != nil && f.cfg.CORS != nil {
corsConfig := &middleware.CORSConfig{
AllowedOrigins: f.cfg.CORS.AllowedOrigins,
AllowedMethods: f.cfg.CORS.AllowedMethods,
AllowedHeaders: f.cfg.CORS.AllowedHeaders,
ExposedHeaders: f.cfg.CORS.ExposedHeaders,
AllowCredentials: f.cfg.CORS.AllowCredentials,
MaxAge: f.cfg.CORS.MaxAge,
}
middlewares = append(middlewares, middleware.CORS(corsConfig))
}
// 5. Timezone 中间件(必需,处理时区)
middlewares = append(middlewares, middleware.Timezone)
return middleware.NewChain(middlewares...)
}