将工厂改成黑盒模式,降低用户使用成本
This commit is contained in:
@@ -3,12 +3,14 @@ package factory
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"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/sms"
|
||||
"git.toowon.com/jimmy/go-common/storage"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
@@ -18,7 +20,13 @@ import (
|
||||
|
||||
// Factory 工厂类,用于从配置创建各种客户端对象
|
||||
type Factory struct {
|
||||
cfg *config.Config
|
||||
cfg *config.Config
|
||||
storage storage.Storage // 存储实例(延迟初始化)
|
||||
logger *logger.Logger // 日志实例(延迟初始化)
|
||||
email *email.Email // 邮件客户端(延迟初始化)
|
||||
sms *sms.SMS // 短信客户端(延迟初始化)
|
||||
db *gorm.DB // 数据库连接(延迟初始化)
|
||||
redis *redis.Client // Redis客户端(延迟初始化)
|
||||
}
|
||||
|
||||
// NewFactory 创建工厂实例
|
||||
@@ -38,37 +46,275 @@ func NewFactoryFromFile(filePath string) (*Factory, error) {
|
||||
return NewFactory(cfg), nil
|
||||
}
|
||||
|
||||
// GetEmailClient 获取邮件客户端(已初始化)
|
||||
// 返回已初始化的邮件客户端对象,可直接使用
|
||||
func (f *Factory) GetEmailClient() (*email.Email, error) {
|
||||
// getEmailClient 获取邮件客户端(内部方法,延迟初始化)
|
||||
func (f *Factory) getEmailClient() (*email.Email, error) {
|
||||
if f.email != nil {
|
||||
return f.email, nil
|
||||
}
|
||||
|
||||
if f.cfg.Email == nil {
|
||||
return nil, fmt.Errorf("email config is nil")
|
||||
}
|
||||
return email.NewEmail(f.cfg.Email)
|
||||
|
||||
e, err := email.NewEmail(f.cfg.Email)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create email client: %w", err)
|
||||
}
|
||||
|
||||
f.email = e
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// GetSMSClient 获取短信客户端(已初始化)
|
||||
// 返回已初始化的短信客户端对象,可直接使用
|
||||
func (f *Factory) GetSMSClient() (*sms.SMS, error) {
|
||||
// SendEmail 发送邮件(黑盒模式)
|
||||
// to: 收件人列表
|
||||
// subject: 邮件主题
|
||||
// body: 邮件正文(纯文本)
|
||||
// htmlBody: HTML正文(可选,如果设置了会优先使用)
|
||||
func (f *Factory) SendEmail(to []string, subject, body string, htmlBody ...string) error {
|
||||
e, err := f.getEmailClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := &email.Message{
|
||||
To: to,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
if len(htmlBody) > 0 && htmlBody[0] != "" {
|
||||
msg.HTMLBody = htmlBody[0]
|
||||
}
|
||||
|
||||
return e.Send(msg)
|
||||
}
|
||||
|
||||
// getSMSClient 获取短信客户端(内部方法,延迟初始化)
|
||||
func (f *Factory) getSMSClient() (*sms.SMS, error) {
|
||||
if f.sms != nil {
|
||||
return f.sms, nil
|
||||
}
|
||||
|
||||
if f.cfg.SMS == nil {
|
||||
return nil, fmt.Errorf("SMS config is nil")
|
||||
}
|
||||
return sms.NewSMS(f.cfg.SMS)
|
||||
|
||||
s, err := sms.NewSMS(f.cfg.SMS)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create SMS client: %w", err)
|
||||
}
|
||||
|
||||
f.sms = s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetLogger 获取日志记录器(已初始化)
|
||||
// 返回已初始化的日志记录器对象,可直接使用
|
||||
func (f *Factory) GetLogger() (*logger.Logger, error) {
|
||||
// SendSMS 发送短信(黑盒模式)
|
||||
// phoneNumbers: 手机号列表
|
||||
// templateParam: 模板参数(map或JSON字符串)
|
||||
// templateCode: 模板代码(可选,如果为空使用配置中的模板代码)
|
||||
func (f *Factory) SendSMS(phoneNumbers []string, templateParam interface{}, templateCode ...string) (*sms.SendResponse, error) {
|
||||
s, err := f.getSMSClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &sms.SendRequest{
|
||||
PhoneNumbers: phoneNumbers,
|
||||
TemplateParam: templateParam,
|
||||
}
|
||||
|
||||
if len(templateCode) > 0 && templateCode[0] != "" {
|
||||
req.TemplateCode = templateCode[0]
|
||||
}
|
||||
|
||||
return s.Send(req)
|
||||
}
|
||||
|
||||
// getLogger 获取日志记录器(内部方法,延迟初始化)
|
||||
func (f *Factory) getLogger() (*logger.Logger, error) {
|
||||
if f.logger != nil {
|
||||
return f.logger, nil
|
||||
}
|
||||
|
||||
var l *logger.Logger
|
||||
var err error
|
||||
if f.cfg.Logger == nil {
|
||||
// 如果没有配置,使用默认配置创建
|
||||
return logger.NewLogger(nil)
|
||||
l, err = logger.NewLogger(nil)
|
||||
} else {
|
||||
l, err = logger.NewLogger(f.cfg.Logger)
|
||||
}
|
||||
return logger.NewLogger(f.cfg.Logger)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create logger: %w", err)
|
||||
}
|
||||
|
||||
f.logger = l
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetDatabase 获取数据库连接对象(已初始化)
|
||||
// 返回已初始化的GORM数据库对象,可直接使用
|
||||
func (f *Factory) GetDatabase() (*gorm.DB, error) {
|
||||
// LogDebug 记录调试日志
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogDebug(message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[DEBUG] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[DEBUG] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
l.Debug(message, args...)
|
||||
} else {
|
||||
l.Debug(message)
|
||||
}
|
||||
}
|
||||
|
||||
// LogDebugf 记录调试日志(带字段)
|
||||
// fields: 日志字段
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogDebugf(fields map[string]interface{}, message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[DEBUG] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[DEBUG] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
l.Debugf(fields, message, args...)
|
||||
}
|
||||
|
||||
// LogInfo 记录信息日志
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogInfo(message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[INFO] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[INFO] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
l.Info(message, args...)
|
||||
} else {
|
||||
l.Info(message)
|
||||
}
|
||||
}
|
||||
|
||||
// LogInfof 记录信息日志(带字段)
|
||||
// fields: 日志字段
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogInfof(fields map[string]interface{}, message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[INFO] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[INFO] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
l.Infof(fields, message, args...)
|
||||
}
|
||||
|
||||
// LogWarn 记录警告日志
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogWarn(message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[WARN] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[WARN] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
l.Warn(message, args...)
|
||||
} else {
|
||||
l.Warn(message)
|
||||
}
|
||||
}
|
||||
|
||||
// LogWarnf 记录警告日志(带字段)
|
||||
// fields: 日志字段
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogWarnf(fields map[string]interface{}, message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[WARN] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[WARN] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
l.Warnf(fields, message, args...)
|
||||
}
|
||||
|
||||
// LogError 记录错误日志
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogError(message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[ERROR] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[ERROR] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
l.Error(message, args...)
|
||||
} else {
|
||||
l.Error(message)
|
||||
}
|
||||
}
|
||||
|
||||
// LogErrorf 记录错误日志(带字段)
|
||||
// fields: 日志字段
|
||||
// message: 日志消息
|
||||
// args: 格式化参数(可选)
|
||||
func (f *Factory) LogErrorf(fields map[string]interface{}, message string, args ...interface{}) {
|
||||
l, err := f.getLogger()
|
||||
if err != nil {
|
||||
// 如果日志初始化失败,使用标准输出
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("[ERROR] "+message+"\n", args...)
|
||||
} else {
|
||||
fmt.Printf("[ERROR] %s\n", message)
|
||||
}
|
||||
return
|
||||
}
|
||||
l.Errorf(fields, message, args...)
|
||||
}
|
||||
|
||||
// getDatabase 获取数据库连接对象(内部方法,延迟初始化)
|
||||
func (f *Factory) getDatabase() (*gorm.DB, error) {
|
||||
if f.db != nil {
|
||||
return f.db, nil
|
||||
}
|
||||
|
||||
if f.cfg.Database == nil {
|
||||
return nil, fmt.Errorf("database config is nil")
|
||||
}
|
||||
@@ -112,12 +358,23 @@ func (f *Factory) GetDatabase() (*gorm.DB, error) {
|
||||
sqlDB.SetConnMaxLifetime(time.Duration(f.cfg.Database.ConnMaxLifetime) * time.Second)
|
||||
}
|
||||
|
||||
f.db = db
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// GetRedisClient 获取Redis客户端对象(已初始化)
|
||||
// 返回已初始化的Redis客户端对象,可直接使用
|
||||
func (f *Factory) GetRedisClient() (*redis.Client, error) {
|
||||
// GetDatabase 获取数据库连接对象(已初始化)
|
||||
// 返回已初始化的GORM数据库对象,可直接使用
|
||||
// 注意:数据库保持返回GORM对象,因为GORM已经提供了很好的抽象
|
||||
func (f *Factory) GetDatabase() (*gorm.DB, error) {
|
||||
return f.getDatabase()
|
||||
}
|
||||
|
||||
// getRedisClient 获取Redis客户端对象(内部方法,延迟初始化)
|
||||
func (f *Factory) getRedisClient() (*redis.Client, error) {
|
||||
if f.redis != nil {
|
||||
return f.redis, nil
|
||||
}
|
||||
|
||||
if f.cfg.Redis == nil {
|
||||
return nil, fmt.Errorf("redis config is nil")
|
||||
}
|
||||
@@ -169,17 +426,155 @@ func (f *Factory) GetRedisClient() (*redis.Client, error) {
|
||||
return nil, fmt.Errorf("failed to connect to redis: %w", err)
|
||||
}
|
||||
|
||||
f.redis = client
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// GetRedisConfig 获取Redis配置(用于创建Redis客户端)
|
||||
// 返回Redis配置对象,调用方可以使用此配置创建Redis客户端
|
||||
// 注意:推荐使用 GetRedisClient 方法直接获取已初始化的客户端
|
||||
func (f *Factory) GetRedisConfig() *config.RedisConfig {
|
||||
return f.cfg.Redis
|
||||
// RedisGet 获取Redis值(黑盒模式)
|
||||
// key: Redis键
|
||||
func (f *Factory) RedisGet(ctx context.Context, key string) (string, error) {
|
||||
client, err := f.getRedisClient()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
result, err := client.Get(ctx, key).Result()
|
||||
if err == redis.Nil {
|
||||
return "", nil // key不存在,返回空字符串
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get redis key: %w", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// RedisSet 设置Redis值(黑盒模式)
|
||||
// key: Redis键
|
||||
// value: Redis值
|
||||
// expiration: 过期时间(可选,0表示不过期)
|
||||
func (f *Factory) RedisSet(ctx context.Context, key string, value interface{}, expiration ...time.Duration) error {
|
||||
client, err := f.getRedisClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var exp time.Duration
|
||||
if len(expiration) > 0 {
|
||||
exp = expiration[0]
|
||||
}
|
||||
|
||||
err = client.Set(ctx, key, value, exp).Err()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set redis key: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RedisDelete 删除Redis键(黑盒模式)
|
||||
// keys: Redis键列表
|
||||
func (f *Factory) RedisDelete(ctx context.Context, keys ...string) error {
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := f.getRedisClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = client.Del(ctx, keys...).Err()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete redis keys: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RedisExists 检查Redis键是否存在(黑盒模式)
|
||||
// key: Redis键
|
||||
func (f *Factory) RedisExists(ctx context.Context, key string) (bool, error) {
|
||||
client, err := f.getRedisClient()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
count, err := client.Exists(ctx, key).Result()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check redis key existence: %w", err)
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// GetConfig 获取配置对象
|
||||
func (f *Factory) GetConfig() *config.Config {
|
||||
return f.cfg
|
||||
}
|
||||
|
||||
// getStorage 获取存储实例(内部方法,延迟初始化)
|
||||
func (f *Factory) getStorage() (storage.Storage, error) {
|
||||
if f.storage != nil {
|
||||
return f.storage, nil
|
||||
}
|
||||
|
||||
// 根据配置自动选择存储类型
|
||||
// 优先级:MinIO > OSS
|
||||
var storageType storage.StorageType
|
||||
if f.cfg.MinIO != nil {
|
||||
storageType = storage.StorageTypeMinIO
|
||||
} else if f.cfg.OSS != nil {
|
||||
storageType = storage.StorageTypeOSS
|
||||
} else {
|
||||
return nil, fmt.Errorf("no storage config found (OSS or MinIO)")
|
||||
}
|
||||
|
||||
// 创建存储实例
|
||||
s, err := storage.NewStorage(storageType, f.cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create storage: %w", err)
|
||||
}
|
||||
|
||||
f.storage = s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// UploadFile 上传文件
|
||||
// ctx: 上下文
|
||||
// objectKey: 对象键(文件路径)
|
||||
// reader: 文件内容
|
||||
// contentType: 文件类型(可选)
|
||||
// 返回文件访问URL和错误
|
||||
func (f *Factory) UploadFile(ctx context.Context, objectKey string, reader io.Reader, contentType ...string) (string, error) {
|
||||
s, err := f.getStorage()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
err = s.Upload(ctx, objectKey, reader, contentType...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to upload file: %w", err)
|
||||
}
|
||||
|
||||
// 获取文件URL
|
||||
url, err := s.GetURL(objectKey, 0)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get file URL: %w", err)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// GetFileURL 获取文件访问URL(Show方法)
|
||||
// objectKey: 对象键
|
||||
// expires: 过期时间(秒),0表示永久有效
|
||||
func (f *Factory) GetFileURL(objectKey string, expires int64) (string, error) {
|
||||
s, err := f.getStorage()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return s.GetURL(objectKey, expires)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user