修改对象的获取方式

This commit is contained in:
2025-11-30 13:50:28 +08:00
parent a655640ab2
commit 7585b8e9da
6 changed files with 279 additions and 73 deletions

View File

@@ -29,7 +29,7 @@
提供阿里云短信发送功能支持模板短信和批量发送使用Go标准库实现。
### 9. 工厂工具 (factory)
提供从配置直接创建已初始化客户端对象的功能,避免调用方重复实现创建逻辑。
提供从配置文件直接创建已初始化客户端对象的功能,包括数据库、Redis、邮件、短信、日志等避免调用方重复实现创建逻辑。
### 10. 日志工具 (logger)
提供统一的日志记录功能支持多种日志级别和输出方式使用Go标准库实现。
@@ -185,27 +185,33 @@ smsClient.SendSimple(
#### 使用工厂直接获取客户端(推荐)
```go
import (
"git.toowon.com/jimmy/go-common/config"
"git.toowon.com/jimmy/go-common/factory"
)
import "git.toowon.com/jimmy/go-common/factory"
// 加载配置并创建工厂
cfg, _ := config.LoadFromFile("./config.json")
fac := factory.NewFactory(cfg)
// 方式1直接从配置文件创建工厂最推荐
fac, _ := factory.NewFactoryFromFile("./config.json")
// 直接获取数据库对象(已初始化,可直接使用)
db, _ := fac.GetDatabase()
db.Find(&users) // 直接使用,无需再创建连接
// 获取Redis配置用于创建Redis客户端
redisConfig := fac.GetRedisConfig()
// 使用go-redis创建客户端
// rdb := redis.NewClient(&redis.Options{
// Addr: fmt.Sprintf("%s:%d", redisConfig.Host, redisConfig.Port),
// Password: redisConfig.Password,
// DB: redisConfig.Database,
// })
// 直接获取已初始化的客户端(无需重复实现创建逻辑)
emailClient, _ := fac.GetEmailClient()
smsClient, _ := fac.GetSMSClient()
logger, _ := fac.GetLogger()
// 直接使用
emailClient.SendSimple(...)
smsClient.SendSimple(...)
// 获取日志记录器(已初始化,可直接使用)
logger, _ := fac.GetLogger()
logger.Info("Application started")
logger.Error("Error occurred: %v", err)
```
更多示例请查看 [examples](./examples/) 目录。

View File

@@ -12,7 +12,24 @@
## 使用方法
### 1. 创建工厂实例
### 1. 从配置文件直接创建工厂(推荐)
```go
import "git.toowon.com/jimmy/go-common/factory"
// 直接传入配置文件路径,自动加载配置并创建工厂
fac, err := factory.NewFactoryFromFile("./config.json")
if err != nil {
log.Fatal(err)
}
// 直接获取已初始化的对象
db, _ := fac.GetDatabase() // 直接获取数据库对象
logger, _ := fac.GetLogger() // 直接获取日志对象
emailClient, _ := fac.GetEmailClient() // 直接获取邮件客户端
```
### 2. 从配置对象创建工厂
```go
import (
@@ -30,7 +47,38 @@ if err != nil {
fac := factory.NewFactory(cfg)
```
### 2. 获取邮件客户端(已初始化)
### 3. 获取数据库对象(已初始化,推荐
```go
// 直接获取已初始化的数据库对象(*gorm.DB
db, err := fac.GetDatabase()
if err != nil {
log.Fatal(err)
}
// 直接使用,无需再创建连接
var users []User
db.Find(&users)
db.Create(&user)
```
### 4. 获取Redis配置
```go
// 获取Redis配置用于创建Redis客户端
// 注意Go标准库没有Redis客户端需要调用方使用第三方库创建
redisConfig := fac.GetRedisConfig()
if redisConfig != nil {
// 使用go-redis创建客户端示例
// rdb := redis.NewClient(&redis.Options{
// Addr: fmt.Sprintf("%s:%d", redisConfig.Host, redisConfig.Port),
// Password: redisConfig.Password,
// DB: redisConfig.Database,
// })
}
```
### 5. 获取邮件客户端(已初始化)
```go
// 直接获取已初始化的邮件客户端
@@ -47,7 +95,7 @@ err = emailClient.SendSimple(
)
```
### 3. 获取短信客户端(已初始化)
### 6. 获取短信客户端(已初始化)
```go
// 直接获取已初始化的短信客户端
@@ -63,7 +111,7 @@ resp, err := smsClient.SendSimple(
)
```
### 4. 获取日志记录器(已初始化)
### 7. 获取日志记录器(已初始化)
```go
// 直接获取已初始化的日志记录器
@@ -77,7 +125,7 @@ logger.Info("Application started")
logger.Error("Error occurred: %v", err)
```
### 5. 完整示例
### 8. 完整示例
```go
package main
@@ -150,6 +198,17 @@ func main() {
**返回:** 工厂实例
### NewFactoryFromFile(filePath string) (*Factory, error)
从配置文件直接创建工厂实例(便捷方法)。
**参数:**
- `filePath`: 配置文件路径
**返回:** 工厂实例和错误信息
**说明:** 这是推荐的使用方式,一步完成配置加载和工厂创建。
### (f *Factory) GetEmailClient() (*email.Email, error)
获取邮件客户端(已初始化)。
@@ -174,6 +233,27 @@ func main() {
**说明:** 如果日志配置为nil会使用默认配置创建。
### (f *Factory) GetDatabase() (*gorm.DB, error)
获取数据库连接对象(已初始化)。
**返回:** 已初始化的GORM数据库对象和错误信息
**说明:**
- 支持MySQL、PostgreSQL、SQLite
- 自动配置连接池参数
- 数据库时间统一使用UTC时区
### (f *Factory) GetRedisConfig() *config.RedisConfig
获取Redis配置用于创建Redis客户端
**返回:** Redis配置对象可能为nil
**说明:**
- Go标准库没有Redis客户端需要调用方使用第三方库如go-redis/redis创建
- 返回配置对象调用方可以根据配置创建Redis客户端
### (f *Factory) GetConfig() *config.Config
获取配置对象。
@@ -187,30 +267,33 @@ func main() {
```go
// 调用方需要自己实现创建逻辑
cfg, _ := config.LoadFromFile("./config.json")
emailConfig := cfg.GetEmail()
if emailConfig == nil {
log.Fatal("email config is nil")
}
emailClient, err := email.NewEmail(emailConfig)
dsn, _ := cfg.GetDatabaseDSN()
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
// 配置连接池
sqlDB, _ := db.DB()
sqlDB.SetMaxOpenConns(100)
// 才能使用
emailClient.SendSimple(...)
db.Find(&users)
```
### 使用工厂方式(直接获取已初始化对象)
```go
// 直接获取已初始化的对象,无需重复实现
// 方式1直接从配置文件创建最推荐
fac, _ := factory.NewFactoryFromFile("./config.json")
db, _ := fac.GetDatabase() // 直接获取已初始化的数据库对象
// 直接使用
db.Find(&users)
// 方式2从配置对象创建
cfg, _ := config.LoadFromFile("./config.json")
fac := factory.NewFactory(cfg)
emailClient, err := fac.GetEmailClient()
if err != nil {
log.Fatal(err)
}
db, _ := fac.GetDatabase() // 直接获取已初始化的数据库对象
// 直接使用
emailClient.SendSimple(...)
db.Find(&users)
```
## 注意事项

View File

@@ -4,69 +4,86 @@ import (
"fmt"
"log"
"git.toowon.com/jimmy/go-common/config"
"git.toowon.com/jimmy/go-common/factory"
)
func main() {
// 加载配置
cfg, err := config.LoadFromFile("./config/example.json")
// 方式1直接从配置文件创建工厂推荐
fac, err := factory.NewFactoryFromFile("./config/example.json")
if err != nil {
log.Fatal("Failed to load config:", err)
log.Fatal("Failed to create factory:", err)
}
// 创建工厂实例
fac := factory.NewFactory(cfg)
// 直接获取数据库对象(已初始化,可直接使用)
db, err := fac.GetDatabase()
if err != nil {
log.Printf("Database not available: %v", err)
} else {
// 直接使用数据库
var count int64
if err := db.Table("users").Count(&count).Error; err != nil {
log.Printf("Failed to count users: %v", err)
} else {
fmt.Printf("User count: %d\n", count)
}
}
// 示例1获取邮件客户端已初始化可直接使用
fmt.Println("=== Example 1: Get Email Client ===")
// 获取Redis配置用于创建Redis客户端
redisConfig := fac.GetRedisConfig()
if redisConfig != nil {
fmt.Printf("Redis config: %s:%d\n", redisConfig.Host, redisConfig.Port)
// 使用go-redis创建客户端示例
// import "github.com/redis/go-redis/v9"
// rdb := redis.NewClient(&redis.Options{
// Addr: fmt.Sprintf("%s:%d", redisConfig.Host, redisConfig.Port),
// Password: redisConfig.Password,
// DB: redisConfig.Database,
// })
}
// 获取邮件客户端(已初始化,可直接使用)
emailClient, err := fac.GetEmailClient()
if err != nil {
log.Printf("Email client not available: %v", err)
} else {
fmt.Println("Email client created successfully")
// 直接使用,无需再创建
_ = emailClient // 示例中不使用,实际使用时可以直接调用方法
// err = emailClient.SendSimple(
// []string{"recipient@example.com"},
// "测试邮件",
// "这是测试内容",
// )
fmt.Println("Email client is ready to use")
// 直接使用
err = emailClient.SendSimple(
[]string{"recipient@example.com"},
"测试邮件",
"这是测试内容",
)
if err != nil {
log.Printf("Failed to send email: %v", err)
} else {
fmt.Println("Email sent successfully")
}
}
// 示例2获取短信客户端(已初始化,可直接使用)
fmt.Println("\n=== Example 2: Get SMS Client ===")
// 获取短信客户端(已初始化,可直接使用)
smsClient, err := fac.GetSMSClient()
if err != nil {
log.Printf("SMS client not available: %v", err)
} else {
fmt.Println("SMS client created successfully")
// 直接使用,无需再创建
_ = smsClient // 示例中不使用,实际使用时可以直接调用方法
// resp, err := smsClient.SendSimple(
// []string{"13800138000"},
// map[string]string{"code": "123456"},
// )
fmt.Println("SMS client is ready to use")
}
// 示例3访问配置对象
fmt.Println("\n=== Example 3: Access Config Object ===")
cfgObj := fac.GetConfig()
dsn, err := cfgObj.GetDatabaseDSN()
// 直接使用
resp, err := smsClient.SendSimple(
[]string{"13800138000"},
map[string]string{"code": "123456"},
)
if err != nil {
log.Printf("Database DSN not available: %v", err)
log.Printf("Failed to send SMS: %v", err)
} else {
fmt.Printf("Database DSN: %s\n", dsn)
fmt.Printf("SMS sent: %s\n", resp.RequestID)
}
}
redisAddr := cfgObj.GetRedisAddr()
if redisAddr != "" {
fmt.Printf("Redis Address: %s\n", redisAddr)
// 获取日志记录器(已初始化,可直接使用)
logger, err := fac.GetLogger()
if err != nil {
log.Printf("Logger not available: %v", err)
} else {
logger.Info("Application started")
logger.Debug("Debug message")
logger.Warn("Warning message")
logger.Error("Error message")
}
fmt.Println("\nNote: Factory provides initialized clients directly,")
fmt.Println("no need to implement creation logic in your code.")
}

View File

@@ -2,11 +2,16 @@ package factory
import (
"fmt"
"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"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// Factory 工厂类,用于从配置创建各种客户端对象
@@ -21,6 +26,16 @@ func NewFactory(cfg *config.Config) *Factory {
}
}
// NewFactoryFromFile 从配置文件创建工厂实例(便捷方法)
// filePath: 配置文件路径
func NewFactoryFromFile(filePath string) (*Factory, error) {
cfg, err := config.LoadFromFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to load config: %w", err)
}
return NewFactory(cfg), nil
}
// GetEmailClient 获取邮件客户端(已初始化)
// 返回已初始化的邮件客户端对象,可直接使用
func (f *Factory) GetEmailClient() (*email.Email, error) {
@@ -49,8 +64,63 @@ func (f *Factory) GetLogger() (*logger.Logger, error) {
return logger.NewLogger(f.cfg.Logger)
}
// GetDatabase 获取数据库连接对象(已初始化)
// 返回已初始化的GORM数据库对象可直接使用
func (f *Factory) GetDatabase() (*gorm.DB, error) {
if f.cfg.Database == nil {
return nil, fmt.Errorf("database config is nil")
}
// 获取DSN
dsn, err := f.cfg.GetDatabaseDSN()
if err != nil {
return nil, fmt.Errorf("failed to get DSN: %w", err)
}
// 根据数据库类型创建连接
var db *gorm.DB
switch f.cfg.Database.Type {
case "mysql":
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
case "postgres":
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
case "sqlite":
db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{})
default:
return nil, fmt.Errorf("unsupported database type: %s", f.cfg.Database.Type)
}
if err != nil {
return nil, fmt.Errorf("failed to connect to database: %w", err)
}
// 配置连接池
sqlDB, err := db.DB()
if err != nil {
return nil, fmt.Errorf("failed to get sql.DB: %w", err)
}
if f.cfg.Database.MaxOpenConns > 0 {
sqlDB.SetMaxOpenConns(f.cfg.Database.MaxOpenConns)
}
if f.cfg.Database.MaxIdleConns > 0 {
sqlDB.SetMaxIdleConns(f.cfg.Database.MaxIdleConns)
}
if f.cfg.Database.ConnMaxLifetime > 0 {
sqlDB.SetConnMaxLifetime(time.Duration(f.cfg.Database.ConnMaxLifetime) * time.Second)
}
return db, nil
}
// GetRedisConfig 获取Redis配置用于创建Redis客户端
// 返回Redis配置对象调用方可以使用此配置创建Redis客户端
// 注意Go标准库没有Redis客户端需要调用方使用第三方库如go-redis/redis创建
func (f *Factory) GetRedisConfig() *config.RedisConfig {
return f.cfg.Redis
}
// GetConfig 获取配置对象
func (f *Factory) GetConfig() *config.Config {
return f.cfg
}

9
go.mod
View File

@@ -10,8 +10,15 @@ require (
require (
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
gorm.io/driver/postgres v1.6.0 // indirect
)

23
go.sum
View File

@@ -1,16 +1,39 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
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=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=