调整工厂模式的方法
This commit is contained in:
@@ -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 获取文件访问URL(Show方法)
|
||||
// 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...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user