1396 lines
43 KiB
Go
1396 lines
43 KiB
Go
package factory
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"time"
|
||
|
||
"git.toowon.com/jimmy/go-common/config"
|
||
"git.toowon.com/jimmy/go-common/email"
|
||
commonhttp "git.toowon.com/jimmy/go-common/http"
|
||
"git.toowon.com/jimmy/go-common/logger"
|
||
"git.toowon.com/jimmy/go-common/middleware"
|
||
"git.toowon.com/jimmy/go-common/migration"
|
||
"git.toowon.com/jimmy/go-common/sms"
|
||
"git.toowon.com/jimmy/go-common/storage"
|
||
"git.toowon.com/jimmy/go-common/tools"
|
||
"github.com/redis/go-redis/v9"
|
||
"gorm.io/driver/mysql"
|
||
"gorm.io/driver/postgres"
|
||
"gorm.io/driver/sqlite"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// ========== HTTP响应结构体(暴露给外部项目使用) ==========
|
||
|
||
// Response 标准响应结构(暴露给外部项目使用)
|
||
// 外部项目可以直接使用 factory.Response 创建响应对象
|
||
//
|
||
// 示例:
|
||
//
|
||
// response := factory.Response{
|
||
// Code: 0,
|
||
// Message: "success",
|
||
// Data: data,
|
||
// }
|
||
type Response = commonhttp.Response
|
||
|
||
// PageResponse 分页响应结构(暴露给外部项目使用)
|
||
// 外部项目可以直接使用 factory.PageResponse 创建分页响应对象
|
||
type PageResponse = commonhttp.PageResponse
|
||
|
||
// PageData 分页数据(暴露给外部项目使用)
|
||
// 外部项目可以直接使用 factory.PageData 创建分页数据对象
|
||
//
|
||
// 示例:
|
||
//
|
||
// pageData := &factory.PageData{
|
||
// List: users,
|
||
// Total: 100,
|
||
// Page: 1,
|
||
// PageSize: 20,
|
||
// }
|
||
// fac.Success(w, pageData)
|
||
type PageData = commonhttp.PageData
|
||
|
||
// ========== HTTP请求结构体(暴露给外部项目使用) ==========
|
||
|
||
// PaginationRequest 分页请求结构(暴露给外部项目使用)
|
||
// 外部项目可以直接使用 factory.PaginationRequest 创建分页请求对象
|
||
//
|
||
// 示例:
|
||
//
|
||
// type ListUserRequest struct {
|
||
// Keyword string `json:"keyword"`
|
||
// factory.PaginationRequest // 嵌入分页请求结构
|
||
// }
|
||
type PaginationRequest = commonhttp.PaginationRequest
|
||
|
||
// ========== Time工具结构体(暴露给外部项目使用) ==========
|
||
|
||
// TimeInfo 详细时间信息结构(暴露给外部项目使用)
|
||
// 外部项目可以直接使用 factory.TimeInfo 创建时间信息对象
|
||
type TimeInfo = tools.TimeInfo
|
||
|
||
// 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
|
||
storage storage.Storage // 存储实例(延迟初始化)
|
||
logger *logger.Logger // 日志实例(延迟初始化)
|
||
email *email.Email // 邮件客户端(延迟初始化)
|
||
sms *sms.SMS // 短信客户端(延迟初始化)
|
||
db *gorm.DB // 数据库连接(延迟初始化)
|
||
redis *redis.Client // Redis客户端(延迟初始化)
|
||
}
|
||
|
||
// NewFactory 创建工厂实例
|
||
func NewFactory(cfg *config.Config) *Factory {
|
||
return &Factory{
|
||
cfg: cfg,
|
||
}
|
||
}
|
||
|
||
// 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) {
|
||
if f.email != nil {
|
||
return f.email, nil
|
||
}
|
||
|
||
f.email = email.NewEmail(f.cfg)
|
||
return f.email, nil
|
||
}
|
||
|
||
// SendEmail 发送邮件(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的SMTP配置发送邮件
|
||
// 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
|
||
}
|
||
return e.SendEmail(to, subject, body, htmlBody...)
|
||
}
|
||
|
||
// getSMSClient 获取短信客户端(内部方法,延迟初始化)
|
||
func (f *Factory) getSMSClient() (*sms.SMS, error) {
|
||
if f.sms != nil {
|
||
return f.sms, nil
|
||
}
|
||
|
||
f.sms = sms.NewSMS(f.cfg)
|
||
return f.sms, nil
|
||
}
|
||
|
||
// 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
|
||
}
|
||
return s.SendSMS(phoneNumbers, templateParam, templateCode...)
|
||
}
|
||
|
||
// 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 {
|
||
// 如果没有配置,使用默认配置创建
|
||
l, err = logger.NewLogger(nil)
|
||
} else {
|
||
l, err = logger.NewLogger(f.cfg.Logger)
|
||
}
|
||
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to create logger: %w", err)
|
||
}
|
||
|
||
f.logger = l
|
||
return l, nil
|
||
}
|
||
|
||
// 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 记录调试日志(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录调试日志(带字段,黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录信息日志(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录信息日志(带字段,黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录警告日志(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录警告日志(带字段,黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录错误日志(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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 记录错误日志(带字段,黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的logger配置
|
||
// 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")
|
||
}
|
||
|
||
// 获取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)
|
||
}
|
||
|
||
f.db = db
|
||
return db, nil
|
||
}
|
||
|
||
// GetDatabase 获取数据库连接对象(推荐使用)
|
||
// 返回已初始化的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()
|
||
}
|
||
|
||
// 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")
|
||
}
|
||
|
||
// 获取Redis地址
|
||
addr := f.cfg.GetRedisAddr()
|
||
if addr == "" {
|
||
return nil, fmt.Errorf("redis address is empty")
|
||
}
|
||
|
||
// 设置默认值
|
||
redisConfig := f.cfg.Redis
|
||
if redisConfig.PoolSize == 0 {
|
||
redisConfig.PoolSize = 10 // 默认连接池大小
|
||
}
|
||
if redisConfig.MinIdleConns == 0 {
|
||
redisConfig.MinIdleConns = 5 // 默认最小空闲连接数
|
||
}
|
||
if redisConfig.DialTimeout == 0 {
|
||
redisConfig.DialTimeout = 5 // 默认连接超时5秒
|
||
}
|
||
if redisConfig.ReadTimeout == 0 {
|
||
redisConfig.ReadTimeout = 3 // 默认读取超时3秒
|
||
}
|
||
if redisConfig.WriteTimeout == 0 {
|
||
redisConfig.WriteTimeout = 3 // 默认写入超时3秒
|
||
}
|
||
|
||
// 创建Redis客户端
|
||
client := redis.NewClient(&redis.Options{
|
||
Addr: addr,
|
||
Password: redisConfig.Password,
|
||
DB: redisConfig.Database,
|
||
PoolSize: redisConfig.PoolSize,
|
||
MinIdleConns: redisConfig.MinIdleConns,
|
||
MaxRetries: redisConfig.MaxRetries,
|
||
DialTimeout: time.Duration(redisConfig.DialTimeout) * time.Second,
|
||
ReadTimeout: time.Duration(redisConfig.ReadTimeout) * time.Second,
|
||
WriteTimeout: time.Duration(redisConfig.WriteTimeout) * time.Second,
|
||
})
|
||
|
||
// 测试连接
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(redisConfig.DialTimeout)*time.Second)
|
||
defer cancel()
|
||
|
||
_, err := client.Ping(ctx).Result()
|
||
if err != nil {
|
||
client.Close() // 连接失败时关闭客户端
|
||
return nil, fmt.Errorf("failed to connect to redis: %w", err)
|
||
}
|
||
|
||
f.redis = client
|
||
return client, nil
|
||
}
|
||
|
||
// 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值(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的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值(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的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键(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的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键是否存在(黑盒模式,推荐使用)
|
||
// 自动使用配置文件中的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 上传文件(黑盒模式,推荐使用)
|
||
// 自动根据配置选择存储类型(OSS 或 MinIO),无需关心内部实现
|
||
// 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(黑盒模式,推荐使用)
|
||
// 自动根据配置选择存储类型,返回文件的访问URL
|
||
// 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)
|
||
}
|
||
|
||
// 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...)
|
||
}
|
||
|
||
// RunMigrations 执行数据库迁移(黑盒模式,推荐使用)
|
||
// 自动发现并执行指定目录下的所有迁移文件
|
||
// migrationsDir: 迁移文件目录(如 "migrations" 或 "scripts/sql")
|
||
//
|
||
// 支持的文件命名格式:
|
||
// - 数字前缀: 01_init_schema.sql
|
||
// - 时间戳: 20240101000001_create_users.sql
|
||
// - 带.up后缀: 20240101000001_create_users.up.sql
|
||
//
|
||
// 示例:
|
||
//
|
||
// fac, _ := factory.NewFactoryFromFile("config.json")
|
||
// err := fac.RunMigrations("migrations")
|
||
// if err != nil {
|
||
// log.Fatal(err)
|
||
// }
|
||
func (f *Factory) RunMigrations(migrationsDir string) error {
|
||
// 获取数据库连接
|
||
db, err := f.getDatabase()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to get database: %w", err)
|
||
}
|
||
|
||
// 创建迁移器(传入数据库类型,性能更好)
|
||
dbType := "mysql" // 默认值
|
||
if f.cfg.Database != nil && f.cfg.Database.Type != "" {
|
||
dbType = f.cfg.Database.Type
|
||
}
|
||
migrator := migration.NewMigratorWithType(db, dbType)
|
||
|
||
// 自动发现并加载迁移文件
|
||
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
||
if err != nil {
|
||
return fmt.Errorf("failed to load migrations: %w", err)
|
||
}
|
||
|
||
if len(migrations) == 0 {
|
||
f.LogInfo("在目录 '%s' 中没有找到迁移文件", migrationsDir)
|
||
return nil
|
||
}
|
||
|
||
migrator.AddMigrations(migrations...)
|
||
|
||
// 执行迁移
|
||
if err := migrator.Up(); err != nil {
|
||
return fmt.Errorf("failed to run migrations: %w", err)
|
||
}
|
||
|
||
f.LogInfo("迁移执行成功: %d 个迁移文件", len(migrations))
|
||
return nil
|
||
}
|
||
|
||
// GetMigrationStatus 获取迁移状态(黑盒模式,推荐使用)
|
||
// migrationsDir: 迁移文件目录
|
||
// 返回迁移状态列表,包含版本、描述、是否已应用等信息
|
||
//
|
||
// 示例:
|
||
//
|
||
// fac, _ := factory.NewFactoryFromFile("config.json")
|
||
// status, err := fac.GetMigrationStatus("migrations")
|
||
// if err != nil {
|
||
// log.Fatal(err)
|
||
// }
|
||
// for _, s := range status {
|
||
// fmt.Printf("Version: %s, Applied: %v\n", s.Version, s.Applied)
|
||
// }
|
||
func (f *Factory) GetMigrationStatus(migrationsDir string) ([]migration.MigrationStatus, error) {
|
||
// 获取数据库连接
|
||
db, err := f.getDatabase()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get database: %w", err)
|
||
}
|
||
|
||
// 创建迁移器(传入数据库类型,性能更好)
|
||
dbType := "mysql" // 默认值
|
||
if f.cfg.Database != nil && f.cfg.Database.Type != "" {
|
||
dbType = f.cfg.Database.Type
|
||
}
|
||
migrator := migration.NewMigratorWithType(db, dbType)
|
||
|
||
// 加载迁移文件
|
||
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to load migrations: %w", err)
|
||
}
|
||
|
||
migrator.AddMigrations(migrations...)
|
||
|
||
// 获取状态
|
||
status, err := migrator.Status()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get migration status: %w", err)
|
||
}
|
||
|
||
return status, nil
|
||
}
|
||
|
||
// ========== HTTP响应方法(黑盒模式,推荐使用) ==========
|
||
//
|
||
// 这些方法直接调用 http 包的公共方法,保持低耦合。
|
||
// 推荐直接使用 factory.Success() 等方法,而不是通过 handler。
|
||
|
||
// Success 成功响应(黑盒模式,推荐使用)
|
||
// w: ResponseWriter
|
||
// data: 响应数据,可以为nil
|
||
// message: 响应消息(可选),如果为空则使用默认消息 "success"
|
||
//
|
||
// 示例:
|
||
//
|
||
// fac, _ := factory.NewFactoryFromFile("config.json")
|
||
// http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
|
||
// fac.Success(w, user) // 只有数据
|
||
// fac.Success(w, user, "查询成功") // 数据+消息
|
||
// })
|
||
func (f *Factory) Success(w http.ResponseWriter, data interface{}, message ...string) {
|
||
commonhttp.Success(w, data, message...)
|
||
}
|
||
|
||
// SuccessPage 分页成功响应(黑盒模式,推荐使用)
|
||
// w: ResponseWriter
|
||
// list: 数据列表
|
||
// total: 总记录数
|
||
// page: 当前页码
|
||
// pageSize: 每页大小
|
||
// message: 响应消息(可选),如果为空则使用默认消息 "success"
|
||
func (f *Factory) SuccessPage(w http.ResponseWriter, list interface{}, total int64, page, pageSize int, message ...string) {
|
||
commonhttp.SuccessPage(w, list, total, page, pageSize, message...)
|
||
}
|
||
|
||
// Error 错误响应(黑盒模式,推荐使用)
|
||
// w: ResponseWriter
|
||
// code: 业务错误码,非0表示业务错误
|
||
// message: 错误消息
|
||
func (f *Factory) Error(w http.ResponseWriter, code int, message string) {
|
||
commonhttp.Error(w, code, message)
|
||
}
|
||
|
||
// SystemError 系统错误响应(返回HTTP 500)(黑盒模式,推荐使用)
|
||
// w: ResponseWriter
|
||
// message: 错误消息
|
||
func (f *Factory) SystemError(w http.ResponseWriter, message string) {
|
||
commonhttp.SystemError(w, message)
|
||
}
|
||
|
||
// ========== HTTP请求解析方法(黑盒模式,推荐使用) ==========
|
||
//
|
||
// 这些方法直接调用 http 包的公共方法,保持低耦合。
|
||
// 推荐直接使用 factory.ParseJSON()、factory.GetQuery() 等方法。
|
||
|
||
// ParseJSON 解析JSON请求体(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// v: 目标结构体指针
|
||
//
|
||
// 示例:
|
||
//
|
||
// var req struct {
|
||
// Name string `json:"name"`
|
||
// }
|
||
// if err := fac.ParseJSON(r, &req); err != nil {
|
||
// fac.Error(w, 400, "请求参数解析失败")
|
||
// return
|
||
// }
|
||
func (f *Factory) ParseJSON(r *http.Request, v interface{}) error {
|
||
return commonhttp.ParseJSON(r, v)
|
||
}
|
||
|
||
// ParsePaginationRequest 从请求中解析分页参数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// 支持从查询参数和form表单中解析
|
||
// 优先级:查询参数 > form表单
|
||
//
|
||
// 示例:
|
||
//
|
||
// pagination := fac.ParsePaginationRequest(r)
|
||
// page := pagination.GetPage()
|
||
// pageSize := pagination.GetSize()
|
||
func (f *Factory) ParsePaginationRequest(r *http.Request) *PaginationRequest {
|
||
return commonhttp.ParsePaginationRequest(r)
|
||
}
|
||
|
||
// GetQuery 获取查询参数(字符串)(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetQuery(r *http.Request, key, defaultValue string) string {
|
||
return commonhttp.GetQuery(r, key, defaultValue)
|
||
}
|
||
|
||
// GetQueryInt 获取整数查询参数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetQueryInt(r *http.Request, key string, defaultValue int) int {
|
||
return commonhttp.GetQueryInt(r, key, defaultValue)
|
||
}
|
||
|
||
// GetQueryInt64 获取int64查询参数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetQueryInt64(r *http.Request, key string, defaultValue int64) int64 {
|
||
return commonhttp.GetQueryInt64(r, key, defaultValue)
|
||
}
|
||
|
||
// GetQueryBool 获取布尔查询参数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetQueryBool(r *http.Request, key string, defaultValue bool) bool {
|
||
return commonhttp.GetQueryBool(r, key, defaultValue)
|
||
}
|
||
|
||
// GetQueryFloat64 获取float64查询参数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetQueryFloat64(r *http.Request, key string, defaultValue float64) float64 {
|
||
return commonhttp.GetQueryFloat64(r, key, defaultValue)
|
||
}
|
||
|
||
// GetFormValue 获取表单值(字符串)(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetFormValue(r *http.Request, key, defaultValue string) string {
|
||
return commonhttp.GetFormValue(r, key, defaultValue)
|
||
}
|
||
|
||
// GetFormInt 获取表单整数(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetFormInt(r *http.Request, key string, defaultValue int) int {
|
||
return commonhttp.GetFormInt(r, key, defaultValue)
|
||
}
|
||
|
||
// GetFormInt64 获取表单int64(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetFormInt64(r *http.Request, key string, defaultValue int64) int64 {
|
||
return commonhttp.GetFormInt64(r, key, defaultValue)
|
||
}
|
||
|
||
// GetFormBool 获取表单布尔值(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 参数名
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetFormBool(r *http.Request, key string, defaultValue bool) bool {
|
||
return commonhttp.GetFormBool(r, key, defaultValue)
|
||
}
|
||
|
||
// GetHeader 获取请求头(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// key: 请求头名称
|
||
// defaultValue: 默认值
|
||
func (f *Factory) GetHeader(r *http.Request, key, defaultValue string) string {
|
||
return commonhttp.GetHeader(r, key, defaultValue)
|
||
}
|
||
|
||
// GetTimezone 从请求的context中获取时区(黑盒模式,推荐使用)
|
||
// r: HTTP请求
|
||
// 如果使用了middleware.Timezone中间件,可以从context中获取时区信息
|
||
// 如果未设置,返回默认时区 AsiaShanghai
|
||
func (f *Factory) GetTimezone(r *http.Request) string {
|
||
return commonhttp.GetTimezone(r)
|
||
}
|
||
|
||
// ========== Tools工具方法(黑盒模式,推荐使用) ==========
|
||
//
|
||
// 这些方法直接调用 tools 包的公共方法,保持低耦合。
|
||
// factory 只负责方法暴露,具体业务在 tools 包中实现。
|
||
|
||
// ========== Version 版本工具 ==========
|
||
|
||
// GetVersion 获取版本号(黑盒模式,推荐使用)
|
||
// 优先从环境变量 DOCKER_TAG 或 VERSION 中读取
|
||
// 如果没有设置环境变量,则使用默认版本号
|
||
func (f *Factory) GetVersion() string {
|
||
return tools.GetVersion()
|
||
}
|
||
|
||
// ========== Money 金额工具 ==========
|
||
|
||
// GetMoneyCalculator 获取金额计算器(黑盒模式,推荐使用)
|
||
// 返回金额计算器实例,可用于金额计算操作
|
||
func (f *Factory) GetMoneyCalculator() *tools.MoneyCalculator {
|
||
return tools.NewMoneyCalculator()
|
||
}
|
||
|
||
// YuanToCents 元转分(黑盒模式,推荐使用)
|
||
func (f *Factory) YuanToCents(yuan float64) int64 {
|
||
return tools.YuanToCents(yuan)
|
||
}
|
||
|
||
// CentsToYuan 分转元(黑盒模式,推荐使用)
|
||
func (f *Factory) CentsToYuan(cents int64) float64 {
|
||
return tools.CentsToYuan(cents)
|
||
}
|
||
|
||
// FormatYuan 格式化显示金额(分转元,保留2位小数)(黑盒模式,推荐使用)
|
||
func (f *Factory) FormatYuan(cents int64) string {
|
||
return tools.FormatYuan(cents)
|
||
}
|
||
|
||
// ========== DateTime 日期时间工具 ==========
|
||
|
||
// Now 获取当前时间(使用指定时区)(黑盒模式,推荐使用)
|
||
func (f *Factory) Now(timezone ...string) time.Time {
|
||
return tools.Now(timezone...)
|
||
}
|
||
|
||
// ParseDateTime 解析日期时间字符串(2006-01-02 15:04:05)(黑盒模式,推荐使用)
|
||
func (f *Factory) ParseDateTime(value string, timezone ...string) (time.Time, error) {
|
||
return tools.ParseDateTime(value, timezone...)
|
||
}
|
||
|
||
// ParseDate 解析日期字符串(2006-01-02)(黑盒模式,推荐使用)
|
||
func (f *Factory) ParseDate(value string, timezone ...string) (time.Time, error) {
|
||
return tools.ParseDate(value, timezone...)
|
||
}
|
||
|
||
// FormatDateTime 格式化日期时间(2006-01-02 15:04:05)(黑盒模式,推荐使用)
|
||
func (f *Factory) FormatDateTime(t time.Time, timezone ...string) string {
|
||
return tools.FormatDateTime(t, timezone...)
|
||
}
|
||
|
||
// FormatDate 格式化日期(2006-01-02)(黑盒模式,推荐使用)
|
||
func (f *Factory) FormatDate(t time.Time, timezone ...string) string {
|
||
return tools.FormatDate(t, timezone...)
|
||
}
|
||
|
||
// FormatTime 格式化时间(15:04:05)(黑盒模式,推荐使用)
|
||
func (f *Factory) FormatTime(t time.Time, timezone ...string) string {
|
||
return tools.FormatTime(t, timezone...)
|
||
}
|
||
|
||
// ToUnix 转换为Unix时间戳(黑盒模式,推荐使用)
|
||
func (f *Factory) ToUnix(t time.Time) int64 {
|
||
return tools.ToUnix(t)
|
||
}
|
||
|
||
// FromUnix 从Unix时间戳创建时间(黑盒模式,推荐使用)
|
||
func (f *Factory) FromUnix(sec int64, timezone ...string) time.Time {
|
||
return tools.FromUnix(sec, timezone...)
|
||
}
|
||
|
||
// ToUnixMilli 转换为Unix毫秒时间戳(黑盒模式,推荐使用)
|
||
func (f *Factory) ToUnixMilli(t time.Time) int64 {
|
||
return tools.ToUnixMilli(t)
|
||
}
|
||
|
||
// FromUnixMilli 从Unix毫秒时间戳创建时间(黑盒模式,推荐使用)
|
||
func (f *Factory) FromUnixMilli(msec int64, timezone ...string) time.Time {
|
||
return tools.FromUnixMilli(msec, timezone...)
|
||
}
|
||
|
||
// AddDays 添加天数(黑盒模式,推荐使用)
|
||
func (f *Factory) AddDays(t time.Time, days int) time.Time {
|
||
return tools.AddDays(t, days)
|
||
}
|
||
|
||
// AddMonths 添加月数(黑盒模式,推荐使用)
|
||
func (f *Factory) AddMonths(t time.Time, months int) time.Time {
|
||
return tools.AddMonths(t, months)
|
||
}
|
||
|
||
// AddYears 添加年数(黑盒模式,推荐使用)
|
||
func (f *Factory) AddYears(t time.Time, years int) time.Time {
|
||
return tools.AddYears(t, years)
|
||
}
|
||
|
||
// StartOfDay 获取一天的开始时间(00:00:00)(黑盒模式,推荐使用)
|
||
func (f *Factory) StartOfDay(t time.Time, timezone ...string) time.Time {
|
||
return tools.StartOfDay(t, timezone...)
|
||
}
|
||
|
||
// EndOfDay 获取一天的结束时间(23:59:59.999999999)(黑盒模式,推荐使用)
|
||
func (f *Factory) EndOfDay(t time.Time, timezone ...string) time.Time {
|
||
return tools.EndOfDay(t, timezone...)
|
||
}
|
||
|
||
// StartOfMonth 获取月份的开始时间(黑盒模式,推荐使用)
|
||
func (f *Factory) StartOfMonth(t time.Time, timezone ...string) time.Time {
|
||
return tools.StartOfMonth(t, timezone...)
|
||
}
|
||
|
||
// EndOfMonth 获取月份的结束时间(黑盒模式,推荐使用)
|
||
func (f *Factory) EndOfMonth(t time.Time, timezone ...string) time.Time {
|
||
return tools.EndOfMonth(t, timezone...)
|
||
}
|
||
|
||
// StartOfYear 获取年份的开始时间(黑盒模式,推荐使用)
|
||
func (f *Factory) StartOfYear(t time.Time, timezone ...string) time.Time {
|
||
return tools.StartOfYear(t, timezone...)
|
||
}
|
||
|
||
// EndOfYear 获取年份的结束时间(黑盒模式,推荐使用)
|
||
func (f *Factory) EndOfYear(t time.Time, timezone ...string) time.Time {
|
||
return tools.EndOfYear(t, timezone...)
|
||
}
|
||
|
||
// DiffDays 计算两个时间之间的天数差(黑盒模式,推荐使用)
|
||
func (f *Factory) DiffDays(t1, t2 time.Time) int {
|
||
return tools.DiffDays(t1, t2)
|
||
}
|
||
|
||
// DiffHours 计算两个时间之间的小时差(黑盒模式,推荐使用)
|
||
func (f *Factory) DiffHours(t1, t2 time.Time) int64 {
|
||
return tools.DiffHours(t1, t2)
|
||
}
|
||
|
||
// DiffMinutes 计算两个时间之间的分钟差(黑盒模式,推荐使用)
|
||
func (f *Factory) DiffMinutes(t1, t2 time.Time) int64 {
|
||
return tools.DiffMinutes(t1, t2)
|
||
}
|
||
|
||
// DiffSeconds 计算两个时间之间的秒数差(黑盒模式,推荐使用)
|
||
func (f *Factory) DiffSeconds(t1, t2 time.Time) int64 {
|
||
return tools.DiffSeconds(t1, t2)
|
||
}
|
||
|
||
// ========== Time 时间工具(黑盒模式,推荐使用) ==========
|
||
//
|
||
// 这些方法提供基础时间操作、时间戳、时间判断等功能。
|
||
// 与 DateTime 工具的区别:
|
||
// - DateTime: 专注于时区相关、格式化、解析、UTC转换
|
||
// - Time: 专注于基础时间操作、时间戳、时间判断、时间信息生成
|
||
|
||
// ========== 时间戳方法 ==========
|
||
|
||
// GetTimestamp 获取当前时间戳(秒)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetTimestamp() int64 {
|
||
return tools.GetTimestamp()
|
||
}
|
||
|
||
// GetMillisTimestamp 获取当前时间戳(毫秒)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetMillisTimestamp() int64 {
|
||
return tools.GetMillisTimestamp()
|
||
}
|
||
|
||
// GetUTCTimestamp 获取UTC时间戳(秒)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetUTCTimestamp() int64 {
|
||
return tools.GetUTCTimestamp()
|
||
}
|
||
|
||
// GetUTCTimestampFromTime 从指定时间获取UTC时间戳(秒)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetUTCTimestampFromTime(t time.Time) int64 {
|
||
return tools.GetUTCTimestampFromTime(t)
|
||
}
|
||
|
||
// ========== 格式化方法(自定义格式) ==========
|
||
|
||
// FormatTimeWithLayout 格式化时间(自定义格式)(黑盒模式,推荐使用)
|
||
// layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式
|
||
func (f *Factory) FormatTimeWithLayout(t time.Time, layout string) string {
|
||
return tools.FormatTimeWithLayout(t, layout)
|
||
}
|
||
|
||
// FormatTimeUTC 格式化时间为UTC字符串(ISO 8601格式)(黑盒模式,推荐使用)
|
||
func (f *Factory) FormatTimeUTC(t time.Time) string {
|
||
return tools.FormatTimeUTC(t)
|
||
}
|
||
|
||
// GetCurrentTime 获取当前时间字符串(黑盒模式,推荐使用)
|
||
// 使用默认格式 "2006-01-02 15:04:05"
|
||
func (f *Factory) GetCurrentTime() string {
|
||
return tools.GetCurrentTime()
|
||
}
|
||
|
||
// ========== 解析方法(自定义格式) ==========
|
||
|
||
// ParseTime 解析时间字符串(自定义格式)(黑盒模式,推荐使用)
|
||
// timeStr: 时间字符串
|
||
// layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式
|
||
func (f *Factory) ParseTime(timeStr, layout string) (time.Time, error) {
|
||
return tools.ParseTime(timeStr, layout)
|
||
}
|
||
|
||
// ========== 时间计算(补充 DateTime 的 Add 系列) ==========
|
||
|
||
// AddHours 增加小时数(黑盒模式,推荐使用)
|
||
func (f *Factory) AddHours(t time.Time, hours int) time.Time {
|
||
return tools.AddHours(t, hours)
|
||
}
|
||
|
||
// AddMinutes 增加分钟数(黑盒模式,推荐使用)
|
||
func (f *Factory) AddMinutes(t time.Time, minutes int) time.Time {
|
||
return tools.AddMinutes(t, minutes)
|
||
}
|
||
|
||
// ========== 时间范围(周相关) ==========
|
||
|
||
// GetBeginOfWeek 获取某周的开始时间(周一)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetBeginOfWeek(t time.Time) time.Time {
|
||
return tools.GetBeginOfWeek(t)
|
||
}
|
||
|
||
// GetEndOfWeek 获取某周的结束时间(周日)(黑盒模式,推荐使用)
|
||
func (f *Factory) GetEndOfWeek(t time.Time) time.Time {
|
||
return tools.GetEndOfWeek(t)
|
||
}
|
||
|
||
// ========== 时间判断 ==========
|
||
|
||
// IsToday 判断是否为今天(黑盒模式,推荐使用)
|
||
func (f *Factory) IsToday(t time.Time) bool {
|
||
return tools.IsToday(t)
|
||
}
|
||
|
||
// IsYesterday 判断是否为昨天(黑盒模式,推荐使用)
|
||
func (f *Factory) IsYesterday(t time.Time) bool {
|
||
return tools.IsYesterday(t)
|
||
}
|
||
|
||
// IsTomorrow 判断是否为明天(黑盒模式,推荐使用)
|
||
func (f *Factory) IsTomorrow(t time.Time) bool {
|
||
return tools.IsTomorrow(t)
|
||
}
|
||
|
||
// ========== 时间信息生成 ==========
|
||
|
||
// GenerateTimeInfoWithTimezone 生成详细时间信息(指定时区)(黑盒模式,推荐使用)
|
||
// 返回包含UTC时间、本地时间、时间戳、时区信息等的完整时间信息结构
|
||
func (f *Factory) GenerateTimeInfoWithTimezone(t time.Time, timezone string) TimeInfo {
|
||
return tools.GenerateTimeInfoWithTimezone(t, timezone)
|
||
}
|
||
|
||
// ========== Crypto 加密工具(黑盒模式,推荐使用) ==========
|
||
//
|
||
// 这些方法提供密码加密、哈希计算、随机字符串生成等功能。
|
||
|
||
// ========== 密码加密 ==========
|
||
|
||
// HashPassword 使用bcrypt加密密码(黑盒模式,推荐使用)
|
||
// password: 原始密码
|
||
// 返回: 加密后的密码哈希值
|
||
func (f *Factory) HashPassword(password string) (string, error) {
|
||
return tools.HashPassword(password)
|
||
}
|
||
|
||
// CheckPassword 验证密码(黑盒模式,推荐使用)
|
||
// password: 原始密码
|
||
// hash: 加密后的密码哈希值
|
||
// 返回: 密码是否正确
|
||
func (f *Factory) CheckPassword(password, hash string) bool {
|
||
return tools.CheckPassword(password, hash)
|
||
}
|
||
|
||
// ========== 哈希计算 ==========
|
||
|
||
// MD5 计算MD5哈希值(黑盒模式,推荐使用)
|
||
// text: 要计算哈希的文本
|
||
// 返回: MD5哈希值(十六进制字符串)
|
||
func (f *Factory) MD5(text string) string {
|
||
return tools.MD5(text)
|
||
}
|
||
|
||
// SHA256 计算SHA256哈希值(黑盒模式,推荐使用)
|
||
// text: 要计算哈希的文本
|
||
// 返回: SHA256哈希值(十六进制字符串)
|
||
func (f *Factory) SHA256(text string) string {
|
||
return tools.SHA256(text)
|
||
}
|
||
|
||
// ========== 随机字符串生成 ==========
|
||
|
||
// GenerateRandomString 生成指定长度的随机字符串(黑盒模式,推荐使用)
|
||
// length: 字符串长度
|
||
// 返回: 随机字符串(包含大小写字母和数字)
|
||
func (f *Factory) GenerateRandomString(length int) string {
|
||
return tools.GenerateRandomString(length)
|
||
}
|
||
|
||
// GenerateRandomNumber 生成指定长度的随机数字字符串(黑盒模式,推荐使用)
|
||
// length: 字符串长度
|
||
// 返回: 随机数字字符串
|
||
func (f *Factory) GenerateRandomNumber(length int) string {
|
||
return tools.GenerateRandomNumber(length)
|
||
}
|
||
|
||
// ========== 业务相关随机码生成 ==========
|
||
|
||
// GenerateSMSCode 生成短信验证码(黑盒模式,推荐使用)
|
||
// 返回: 6位数字验证码
|
||
func (f *Factory) GenerateSMSCode() string {
|
||
return tools.GenerateSMSCode()
|
||
}
|
||
|
||
// GenerateOrderNo 生成订单号(黑盒模式,推荐使用)
|
||
// prefix: 订单号前缀
|
||
// 返回: 订单号(格式:前缀+时间戳+6位随机数)
|
||
func (f *Factory) GenerateOrderNo(prefix string) string {
|
||
return tools.GenerateOrderNo(prefix)
|
||
}
|
||
|
||
// GeneratePaymentNo 生成支付单号(黑盒模式,推荐使用)
|
||
// 返回: 支付单号(格式:PAY+时间戳+6位随机数)
|
||
func (f *Factory) GeneratePaymentNo() string {
|
||
return tools.GeneratePaymentNo()
|
||
}
|
||
|
||
// GenerateRefundNo 生成退款单号(黑盒模式,推荐使用)
|
||
// 返回: 退款单号(格式:RF+时间戳+6位随机数)
|
||
func (f *Factory) GenerateRefundNo() string {
|
||
return tools.GenerateRefundNo()
|
||
}
|
||
|
||
// GenerateTransferNo 生成调拨单号(黑盒模式,推荐使用)
|
||
// 返回: 调拨单号(格式:TF+时间戳+6位随机数)
|
||
func (f *Factory) GenerateTransferNo() string {
|
||
return tools.GenerateTransferNo()
|
||
}
|