Files
go-common/README.md

17 KiB
Raw Blame History

GoCommon - Go通用工具类库

这是一个Go语言开发的通用工具类库为其他Go项目提供常用的工具方法集合。

📖 快速链接

🌟 核心特性

🎯 极简调用减少80%重复代码

  • 工厂黑盒模式:一个配置文件,搞定所有服务初始化
  • Handler黑盒模式统一的HTTP请求处理无需重复传递 wr
  • 中间件链式调用:一行代码组合多个中间件

🚀 生产级特性,开箱即用

  • 异步日志:不阻塞请求,高并发性能
  • Panic恢复自动捕获panic防止服务崩溃
  • 令牌桶限流保护API防止滥用
  • 时区自动处理:统一管理时区,避免时间错乱

🔧 灵活可扩展

  • 默认配置即可用:传 nil 使用默认配置
  • 完全可定制:每个功能都支持自定义配置
  • 无侵入设计:可以独立使用任何模块

📦 零外部依赖(核心功能)

  • email、sms 使用 Go 标准库实现
  • 可选依赖gorm数据库、redis、minio

功能模块

1. 数据库迁移工具 (migration)

提供数据库迁移功能支持MySQL、PostgreSQL、SQLite等数据库。

🎯 独立工具,零耦合

  • 编译成独立二进制:go build -o bin/migrate cmd/migrate/main.go
  • 生产环境无需Go环境只需二进制文件
  • 与应用代码完全解耦,可独立部署和执行
  • 支持宿主机和Docker零额外配置

2. 日期转换工具 (datetime)

提供日期时间转换功能,支持时区设定和多种格式转换。

3. HTTP Restful工具 (http)

提供HTTP请求/响应处理工具包含标准化的响应结构、分页支持和HTTP状态码与业务状态码的分离。

4. 中间件工具 (middleware)

提供生产级HTTP中间件包括

  • CORS - 跨域资源共享
  • Timezone - 时区处理
  • Logging - 请求日志记录(支持异步)
  • Recovery - Panic恢复防止服务崩溃
  • RateLimit - 请求限流(令牌桶算法)
  • Chain - 中间件链式组合

5. 配置工具 (config)

提供从外部文件加载配置的功能支持数据库、OSS、Redis、CORS、MinIO等配置。

6. 存储工具 (storage)

提供文件上传和查看功能支持OSS和MinIO两种存储方式并提供HTTP处理器。

7. 邮件工具 (email)

提供SMTP邮件发送功能支持纯文本和HTML邮件使用Go标准库实现。

8. 短信工具 (sms)

提供阿里云短信发送功能支持模板短信和批量发送使用Go标准库实现。

9. 工厂工具 (factory)

提供从配置文件直接创建已初始化客户端对象的功能包括数据库、Redis、邮件、短信、日志等避免调用方重复实现创建逻辑。

10. 日志工具 (logger)

提供统一的日志记录功能支持多种日志级别和输出方式使用Go标准库实现。

安装

1. 配置私有仓库(重要)

由于本项目使用私有 Git 仓库,需要先配置 GOPRIVATE 环境变量:

# 使用 go env 命令配置(推荐,永久生效)
go env -w GOPRIVATE=git.toowon.com

# 验证配置
go env GOPRIVATE

详细配置说明请参考 SETUP.md

遇到问题?请查看 故障排除指南

2. 安装模块

# 安装最新版本(推荐用于开发)
go get git.toowon.com/jimmy/go-common@latest

# 安装特定版本(推荐用于生产)
go get git.toowon.com/jimmy/go-common@v1.0.0

版本管理说明请参考 VERSION.md


📚 文档导航


快速开始

1. 创建配置文件 config.json

{
    "database": {
        "type": "mysql",
        "host": "localhost",
        "port": 3306,
        "user": "root",
        "password": "password",
        "database": "mydb"
    },
    "redis": {
        "host": "localhost",
        "port": 6379
    },
    "logger": {
        "level": "info",
        "output": "both",
        "filePath": "./logs/app.log",
        "async": true
    }
}

2. 使用工厂模式(最简单,推荐)

package main

import (
    "net/http"
    "time"
    
    "git.toowon.com/jimmy/go-common/factory"
    "git.toowon.com/jimmy/go-common/middleware"
    commonhttp "git.toowon.com/jimmy/go-common/http"
)

func main() {
    // 从配置文件创建工厂
    fac, _ := factory.NewFactoryFromFile("./config.json")
    
    // 获取logger
    logger, _ := fac.GetLogger()
    defer logger.Close()
    
    // 配置中间件
    chain := middleware.NewChain(
        middleware.Recovery(&middleware.RecoveryConfig{Logger: logger}),
        middleware.Logging(&middleware.LoggingConfig{Logger: logger}),
        middleware.RateLimitByIP(100, time.Minute),
        middleware.CORS(nil),
        middleware.Timezone,
    )
    
    // 注册API路由
    http.Handle("/api/hello", chain.ThenFunc(handleHello))
    
    // 启动服务
    http.ListenAndServe(":8080", nil)
}

func handleHello(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    
    // 使用工厂记录日志
    // fac.LogInfo("Hello API called")
    
    // 返回响应
    h.Success(map[string]interface{}{
        "message": "Hello, World!",
        "timezone": h.GetTimezone(),
    })
}

3. 运行项目

go run main.go
# 访问 http://localhost:8080/api/hello

使用示例

详细的使用说明请参考各模块的文档:

快速示例

数据库迁移(独立工具,零耦合)

# 1. 复制模板templates/migrate/main.go -> cmd/migrate/main.go
# 2. 编译(生产环境推荐)
go build -o bin/migrate cmd/migrate/main.go

# 3. 使用
./bin/migrate up                              # 使用默认配置
./bin/migrate up -config /path/to/config.json # 指定配置
./bin/migrate status                          # 查看状态

# 迁移文件migrations/20240101000001_create_users.sql
# CREATE TABLE users (id BIGINT PRIMARY KEY AUTO_INCREMENT, ...);

# Docker 中使用(挂载配置,修改无需重启)
# volumes:
#   - ./config.json:/app/config.json:ro
# command: sh -c "./migrate up && ./server"

详细说明数据库迁移完整指南 📖

日期转换

import "git.toowon.com/jimmy/go-common/datetime"

datetime.SetDefaultTimeZone(datetime.AsiaShanghai)
now := datetime.Now()
str := datetime.FormatDateTime(now)

HTTP响应Handler黑盒模式

import (
    "net/http"
    commonhttp "git.toowon.com/jimmy/go-common/http"
)

// 使用Handler黑盒模式
func GetUser(h *commonhttp.Handler) {
    id := h.GetQueryInt64("id", 0)  // 无需传递r
    h.Success(data)                  // 无需传递w
}

http.HandleFunc("/user", commonhttp.HandleFunc(GetUser))

中间件(完整的生产级配置)

import (
    "time"
    "git.toowon.com/jimmy/go-common/config"
    "git.toowon.com/jimmy/go-common/logger"
    "git.toowon.com/jimmy/go-common/middleware"
    commonhttp "git.toowon.com/jimmy/go-common/http"
)

// 方式1简单配置使用默认设置
chain := middleware.NewChain(
    middleware.Recovery(nil),   // Panic恢复
    middleware.Logging(nil),    // 请求日志
    middleware.RateLimit(nil),  // 限流100请求/分钟)
    middleware.CORS(nil),       // CORS允许所有源
    middleware.Timezone,        // 时区处理
)
http.Handle("/api", chain.ThenFunc(yourHandler))

// 方式2生产级配置推荐
// 创建异步logger
myLogger, _ := logger.NewLogger(&config.LoggerConfig{
    Level: "info",
    Output: "both",
    FilePath: "./logs/app.log",
    Async: true,  // 异步模式,不阻塞请求
})

chain := middleware.NewChain(
    middleware.Recovery(&middleware.RecoveryConfig{
        Logger: myLogger,
        EnableStackTrace: true,
    }),
    middleware.Logging(&middleware.LoggingConfig{
        Logger: myLogger,
        SkipPaths: []string{"/health"},
    }),
    middleware.RateLimitByIP(100, time.Minute), // 100请求/分钟
    middleware.CORS(nil),
    middleware.Timezone,
)

// 在Handler中使用
func handler(h *commonhttp.Handler) {
    timezone := h.GetTimezone()  // 获取时区
    h.Success(data)
}

配置管理

import "git.toowon.com/jimmy/go-common/config"

// 从文件加载配置
cfg, err := config.LoadFromFile("./config.json")

// 获取各种配置
dsn, _ := cfg.GetDatabaseDSN()
redisAddr := cfg.GetRedisAddr()
corsConfig := cfg.GetCORS()

文件上传和查看(推荐使用工厂黑盒模式)

import (
    "context"
    "git.toowon.com/jimmy/go-common/factory"
)

fac, _ := factory.NewFactoryFromFile("./config.json")
ctx := context.Background()

// 黑盒模式推荐自动选择OSS或MinIO
file, _ := os.Open("test.jpg")
url, _ := fac.UploadFile(ctx, "images/test.jpg", file, "image/jpeg")

// 获取文件URL
url, _ := fac.GetFileURL("images/test.jpg", 0) // 永久有效
url, _ := fac.GetFileURL("images/test.jpg", 3600) // 1小时后过期

// 或使用存储处理器需要HTTP处理器时
storage, _ := storage.NewStorage(storage.StorageTypeOSS, cfg)
uploadHandler := storage.NewUploadHandler(...)

邮件发送(推荐使用工厂黑盒模式)

import "git.toowon.com/jimmy/go-common/factory"

fac, _ := factory.NewFactoryFromFile("./config.json")

// 黑盒模式(推荐)
fac.SendEmail([]string{"user@example.com"}, "主题", "正文")
fac.SendEmail([]string{"user@example.com"}, "主题", "纯文本", "<h1>HTML内容</h1>")

// 或获取客户端对象(需要高级功能时)
emailClient, _ := fac.GetEmailClient()
emailClient.SendSimple(...)

短信发送(推荐使用工厂黑盒模式)

import "git.toowon.com/jimmy/go-common/factory"

fac, _ := factory.NewFactoryFromFile("./config.json")

// 黑盒模式(推荐)
fac.SendSMS([]string{"13800138000"}, map[string]string{"code": "123456"})

// 或获取客户端对象(需要高级功能时)
smsClient, _ := fac.GetSMSClient()
smsClient.SendSimple(...)

使用工厂(黑盒模式,推荐)

import (
    "context"
    "git.toowon.com/jimmy/go-common/factory"
)

// 从配置文件创建工厂(最推荐)
fac, _ := factory.NewFactoryFromFile("./config.json")
ctx := context.Background()

// 日志(黑盒模式,直接调用)
fac.LogInfo("用户登录成功")
fac.LogError("登录失败: %v", err)

// 邮件发送(黑盒模式,直接调用)
fac.SendEmail([]string{"user@example.com"}, "验证码", "您的验证码是123456")

// 短信发送(黑盒模式,直接调用)
fac.SendSMS([]string{"13800138000"}, map[string]string{"code": "123456"})

// 文件上传黑盒模式自动选择OSS或MinIO
file, _ := os.Open("test.jpg")
url, _ := fac.UploadFile(ctx, "images/test.jpg", file, "image/jpeg")

// 获取文件URL
url, _ := fac.GetFileURL("images/test.jpg", 0) // 永久有效
url, _ := fac.GetFileURL("images/test.jpg", 3600) // 1小时后过期

// Redis操作黑盒模式直接调用
fac.RedisSet(ctx, "key", "value", time.Hour)
value, _ := fac.RedisGet(ctx, "key")
fac.RedisDelete(ctx, "key")

// 数据库(黑盒模式,获取已初始化对象)
db, _ := fac.GetDatabase()
db.Find(&users)

// Redis客户端黑盒模式获取已初始化对象
redisClient, _ := fac.GetRedisClient()
redisClient.HGet(ctx, "key", "field").Result()

更多示例请查看 examples 目录。

版本管理

当前版本:v1.0.0

如何指定版本

go.mod 文件中指定版本:

require (
    git.toowon.com/jimmy/go-common v1.0.0
)

或者使用命令行:

# 使用最新版本
go get git.toowon.com/jimmy/go-common@latest

# 使用特定版本
go get git.toowon.com/jimmy/go-common@v1.0.0

详细版本管理说明请参考 VERSION.md

设计理念

1. 黑盒模式 - 减少重复代码

问题:传统方式需要在每个项目中重复编写初始化代码

// ❌ 传统方式 - 需要在每个项目中重复
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
sqlDB, _ := db.DB()
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxIdleConns(10)
// ... 更多配置

解决:工厂黑盒模式 - 配置文件搞定一切

// ✅ 黑盒模式 - 一行代码搞定
db, _ := factory.NewFactoryFromFile("config.json").GetDatabase()

2. Handler模式 - 统一请求处理

问题:每个处理器都要传递 wr

// ❌ 传统方式
func GetUser(w http.ResponseWriter, r *http.Request) {
    id := r.URL.Query().Get("id")
    json.NewEncoder(w).Encode(data)
}

解决Handler封装 - 简洁优雅

// ✅ Handler模式
func GetUser(h *commonhttp.Handler) {
    id := h.GetQueryInt64("id", 0)
    h.Success(data)
}

3. 中间件链 - 灵活组合

问题:中间件嵌套难以维护

// ❌ 传统方式 - 嵌套地狱
handler := corsMiddleware(
    timezoneMiddleware(
        loggingMiddleware(
            yourHandler
        )
    )
)

解决:链式调用 - 清晰明了

// ✅ 链式组合
chain := middleware.NewChain(
    middleware.CORS(),
    middleware.Timezone,
    middleware.Logging(nil),
)
handler := chain.ThenFunc(yourHandler)

最佳实践

推荐做法

  1. 使用工厂模式:通过配置文件统一管理所有服务
  2. 使用异步日志:生产环境开启 Async: true
  3. 配置Recovery中间件防止panic导致服务崩溃
  4. 合理设置限流:根据实际业务设置限流阈值
  5. 使用时区中间件:统一管理时区,避免时间错乱

避免做法

  1. 不要在循环中创建logger使用全局logger或工厂模式
  2. 不要跳过健康检查日志:高频接口应该配置 SkipPaths
  3. 不要使用同步日志记录大量日志:高并发场景使用异步模式
  4. 不要在生产环境使用 CORS: *:明确指定允许的源

性能优化建议

日志优化

// ✅ 异步模式 - 高并发场景
loggerConfig := &config.LoggerConfig{
    Async: true,        // 异步写入
    BufferSize: 1000,   // 缓冲区大小
}

// ✅ 跳过高频接口
loggingConfig := &middleware.LoggingConfig{
    SkipPaths: []string{"/health", "/metrics", "/ping"},
}

中间件顺序优化

// ✅ 推荐顺序(从外到内)
chain := middleware.NewChain(
    middleware.Recovery(cfg),    // 1. 最外层捕获panic
    middleware.Logging(cfg),     // 2. 记录所有请求
    middleware.RateLimit(cfg),   // 3. 限流保护
    middleware.CORS(cfg),        // 4. CORS处理
    middleware.Timezone,         // 5. 时区处理
)

数据库连接池优化

{
    "database": {
        "maxOpenConns": 100,      // 最大连接数
        "maxIdleConns": 10,       // 最大空闲连接
        "connMaxLifetime": 3600   // 连接最大生存时间(秒)
    }
}

故障排除

问题1循环导入错误

错误import cycle not allowed

解决:使用 middleware.NewCORSConfig() 转换配置

configCORS := cfg.GetCORS()
middlewareCORS := middleware.NewCORSConfig(
    configCORS.AllowedOrigins,
    configCORS.AllowedMethods,
    configCORS.AllowedHeaders,
    configCORS.ExposedHeaders,
    configCORS.AllowCredentials,
    configCORS.MaxAge,
)

问题2IDE显示导入错误

错误could not import git.toowon.com/jimmy/go-common/logger

解决重置Go模块缓存

go clean -modcache
go mod download
# 重启IDE的Language Server

问题3限流不生效

原因:分布式部署下,内存存储只在单机生效

解决分布式场景建议使用Redis实现限流

更多问题请查看 TROUBLESHOOTING.md

贡献指南

欢迎贡献代码!请遵循以下步骤:

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 创建 Pull Request

许可证

MIT License

联系方式

  • 作者Jimmy
  • 邮箱:jimmy@toowon.com
  • 项目地址git.toowon.com/jimmy/go-common

如果这个项目对你有帮助,请给个 Star