企业级 Go Web 开发公共组件库 - 沉淀最佳实践,加速业务开发
- 🎯 接口优先 - 清晰的抽象层,易于扩展和测试
- ⚙️ 配置驱动 - YAML + 环境变量,灵活适配多环境
- 🔌 零侵入设计 - 不绑定特定框架,按需集成
- 🧪 高可测试性 - 完整的 Mock 支持和测试工具
- 📦 开箱即用 - 预配置最佳实践,减少重复工作
- 🚀 生产就绪 - 经过实战验证的企业级组件
| 组件 | 功能 | 核心依赖 |
|---|---|---|
| logger | 结构化日志 | zap |
| conf | 配置管理 | viper |
| database | 数据库连接池 | gorm, postgres |
| cache | Redis 客户端 + 分布式锁 | go-redis/v9 |
| mq | 消息队列抽象层 | Kafka, RocketMQ |
| transport | HTTP/gRPC 服务器 | Fiber v3, gRPC |
| metrics | Prometheus 监控 | prometheus/client_golang |
| middleware | HTTP 中间件 | API Key 认证等 |
| errors | 统一错误处理 | gRPC/HTTP 错误转换 |
| repository | 数据仓储模式 | CRUD, 分页, 聚合 |
| response | 统一响应格式 | HTTP 响应封装 |
| validator | 数据验证 | validator/v10 |
| shutdown | 优雅关闭 | 分优先级资源清理 |
| utils | 工具集 | UUID, Snowflake 等 |
# 在你的项目 go.mod 中添加
replace github.com/aisgo/ais-go-pkg => ../ais-go-pkg
require github.com/aisgo/ais-go-pkg v0.0.0go get github.com/your-org/ais-go-pkg@v1.0.0package main
import (
"github.com/aisgo/ais-go-pkg/logger"
"github.com/aisgo/ais-go-pkg/database/postgres"
"go.uber.org/zap"
)
func main() {
// ================================================================
// 初始化日志
// ================================================================
log := logger.NewLogger(logger.Config{
Level: "info",
Format: "json",
})
// ================================================================
// 连接数据库
// ================================================================
db, err := postgres.NewDB(postgres.Config{
Host: "localhost",
Port: 5432,
User: "user",
Password: "pass",
DBName: "mydb",
}, log)
if err != nil {
log.Fatal("failed to connect database", zap.Error(err))
}
// 其他组件(Redis/MQ/Transport 等)请参考下方“组件详解”中的示例
log.Info("application started successfully")
}package main
import (
"github.com/aisgo/ais-go-pkg/cache"
"github.com/aisgo/ais-go-pkg/cache/redis"
"github.com/aisgo/ais-go-pkg/database/postgres"
"github.com/aisgo/ais-go-pkg/logger"
"github.com/aisgo/ais-go-pkg/mq"
"github.com/aisgo/ais-go-pkg/transport/http"
"github.com/gofiber/fiber/v3"
"go.uber.org/fx"
"gorm.io/gorm"
)
func main() {
app := fx.New(
// ================================================================
// 配置提供
// ================================================================
fx.Provide(
func() logger.Config {
return logger.Config{Level: "info", Format: "json"}
},
func() postgres.Config {
return postgres.Config{
Host: "localhost",
Port: 5432,
User: "user",
Password: "pass",
DBName: "mydb",
}
},
func() redis.Config {
return redis.Config{
Host: "localhost",
Port: 6379,
}
},
func() *mq.Config {
return &mq.Config{
Type: mq.TypeKafka,
Kafka: &mq.KafkaConfig{
Brokers: []string{"localhost:9092"},
},
}
},
// HTTP Server 通过 NewHTTPServer 提供,无需 Module
func() http.Config {
return http.Config{Port: 8080}
},
http.NewHTTPServer,
),
// ================================================================
// 导入组件模块
// ================================================================
logger.Module,
postgres.Module,
cache.Module,
mq.Module,
// ================================================================
// 业务逻辑
// ================================================================
fx.Invoke(func(
log *logger.Logger,
db *gorm.DB,
fiberApp *fiber.App,
// 其他依赖会自动注入
) {
log.Info("application started successfully")
// 使用 db、fiberApp 等组件...
}),
)
app.Run()
}基于 Zap 的高性能日志组件,支持 JSON 和 Console 格式。
import "github.com/aisgo/ais-go-pkg/logger"
log := logger.NewLogger(logger.Config{
Level: "info", // debug, info, warn, error
Format: "json", // json | console
OutputPath: "app.log", // 可选,默认 stdout
})
log.Info("user login",
zap.String("user_id", "123"),
zap.Duration("latency", time.Millisecond*50),
)import (
"github.com/aisgo/ais-go-pkg/logger"
"go.uber.org/fx"
)
app := fx.New(
fx.Provide(func() logger.Config {
return logger.Config{Level: "info", Format: "json"}
}),
logger.Module,
fx.Invoke(func(log *logger.Logger) {
log.Info("application started")
}),
)预配置连接池和日志适配器。
import "github.com/aisgo/ais-go-pkg/database/postgres"
db, err := postgres.NewDB(postgres.Config{
Host: "localhost",
Port: 5432,
User: "postgres",
Password: "secret",
DBName: "mydb",
MaxOpenConns: 25,
MaxIdleConns: 5,
ConnMaxLifetime: time.Hour,
}, log)
// 使用 GORM
type User struct {
ID uint
Name string
}
db.AutoMigrate(&User{})import (
"github.com/aisgo/ais-go-pkg/database/postgres"
"github.com/aisgo/ais-go-pkg/logger"
"go.uber.org/fx"
"gorm.io/gorm"
)
app := fx.New(
fx.Provide(
func() logger.Config { return logger.Config{Level: "info"} },
func() postgres.Config {
return postgres.Config{
Host: "localhost",
Port: 5432,
User: "postgres",
DBName: "mydb",
}
},
),
logger.Module,
postgres.Module,
fx.Invoke(func(db *gorm.DB) {
// 使用 db...
}),
)封装 go-redis/v9,提供分布式锁实现。
import (
"context"
"time"
"github.com/aisgo/ais-go-pkg/cache/redis"
"github.com/aisgo/ais-go-pkg/logger"
)
log := logger.NewLogger(logger.Config{Level: "info"})
client := redis.NewClient(redis.Config{
Host: "localhost",
Port: 6379,
Password: "",
DB: 0,
PoolSize: 10,
MinIdleConns: 5,
}, log)
ctx := context.Background()
_ = client.Set(ctx, "key", "value", time.Hour)
_, _ = client.Get(ctx, "key")
// 分布式锁
lock := client.NewLock("resource:order:123")
if err := lock.Acquire(ctx); err == nil {
defer lock.Release(ctx)
// 临界区代码
}import (
"context"
"time"
"github.com/aisgo/ais-go-pkg/cache"
"github.com/aisgo/ais-go-pkg/cache/redis"
"github.com/aisgo/ais-go-pkg/logger"
"go.uber.org/fx"
)
app := fx.New(
fx.Provide(
func() logger.Config { return logger.Config{Level: "info"} },
func() redis.Config {
return redis.Config{
Host: "localhost",
Port: 6379,
PoolSize: 10,
MinIdleConns: 5,
}
},
),
logger.Module,
cache.Module,
fx.Invoke(func(client *redis.Client) {
ctx := context.Background()
_ = client.Set(ctx, "key", "value", time.Hour)
// 分布式锁
lock := client.NewLock("resource:order:123")
if err := lock.Acquire(ctx); err == nil {
defer lock.Release(ctx)
// 临界区代码
}
}),
)统一接口,支持 Kafka 和 RocketMQ 无缝切换。
import (
"context"
"github.com/aisgo/ais-go-pkg/mq"
_ "github.com/aisgo/ais-go-pkg/mq/kafka" // 注册 Kafka 实现
_ "github.com/aisgo/ais-go-pkg/mq/rocketmq" // 注册 RocketMQ 实现
"go.uber.org/zap"
)
// 配置驱动 - 自动选择实现
cfg := &mq.Config{
Type: mq.TypeKafka,
Kafka: &mq.KafkaConfig{
Brokers: []string{"localhost:9092"},
},
}
producer, _ := mq.NewProducer(cfg, zap.NewNop())
// 发送消息
msg := mq.NewMessage("order-events", []byte(`{"order_id": 123}`)).
WithKey("order-123").
WithProperty("trace-id", "abc123")
_, _ = producer.SendSync(context.Background(), msg)
// 消费消息
consumer, _ := mq.NewConsumer(cfg, zap.NewNop())
_ = consumer.Subscribe("order-events", func(ctx context.Context, msgs []*mq.ConsumedMessage) (mq.ConsumeResult, error) {
// TODO: 处理 msgs
return mq.ConsumeSuccess, nil
})
_ = consumer.Start()import (
"context"
"github.com/aisgo/ais-go-pkg/logger"
"github.com/aisgo/ais-go-pkg/mq"
_ "github.com/aisgo/ais-go-pkg/mq/kafka"
"go.uber.org/fx"
)
app := fx.New(
fx.Provide(
func() logger.Config { return logger.Config{Level: "info"} },
func() *mq.Config {
return &mq.Config{
Type: mq.TypeKafka,
Kafka: &mq.KafkaConfig{
Brokers: []string{"localhost:9092"},
},
}
},
),
logger.Module,
mq.Module, // 自动提供 Producer 和 Consumer
fx.Invoke(func(producer mq.Producer, consumer mq.Consumer) {
// Producer 和 Consumer 会自动注入
// Consumer 会在应用启动时自动开始消费
}),
)import (
aishttp "github.com/aisgo/ais-go-pkg/transport/http"
"github.com/aisgo/ais-go-pkg/logger"
"github.com/gofiber/fiber/v3"
"go.uber.org/fx"
)
app := fx.New(
fx.Provide(
logger.NewNop,
func() aishttp.Config { return aishttp.Config{Port: 8080} },
aishttp.NewHTTPServer,
),
fx.Invoke(func(fiberApp *fiber.App) {
fiberApp.Get("/api/health", func(c fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})
})
}),
)
_ = appimport (
aisgrpc "github.com/aisgo/ais-go-pkg/transport/grpc"
"github.com/aisgo/ais-go-pkg/logger"
"go.uber.org/fx"
"google.golang.org/grpc"
)
app := fx.New(
fx.Provide(
logger.NewNop,
func() aisgrpc.Config { return aisgrpc.Config{Port: 50051, Mode: "microservice"} },
aisgrpc.NewInProcListener,
aisgrpc.NewListener,
aisgrpc.NewServer,
),
fx.Invoke(func(s *grpc.Server) {
// 注册服务
// pb.RegisterYourServiceServer(s, &yourService{})
}),
)
_ = appimport "github.com/aisgo/ais-go-pkg/metrics"
// 注册指标
requestCounter := metrics.NewCounter("http_requests_total", "Total HTTP requests")
requestDuration := metrics.NewHistogram("http_request_duration_seconds", "HTTP request latency")
// 使用
requestCounter.Inc()
requestDuration.Observe(0.05)import (
"github.com/aisgo/ais-go-pkg/metrics"
"go.uber.org/fx"
)
app := fx.New(
metrics.Module,
fx.Invoke(func() {
// 注册指标
requestCounter := metrics.NewCounter("http_requests_total", "Total HTTP requests")
requestCounter.Inc()
}),
)提供通用 CRUD、分页、聚合等数据访问模式。
import "github.com/aisgo/ais-go-pkg/repository"
type UserRepository struct {
repository.BaseRepository[User]
}
repo := &UserRepository{
BaseRepository: repository.NewBaseRepository[User](db),
}
// CRUD 操作
user := &User{Name: "Alice"}
repo.Create(ctx, user)
// 分页查询
page := repo.Paginate(ctx, repository.PageRequest{
Page: 1,
PageSize: 10,
}, repository.WithCondition("age > ?", 18))Repository 默认强制租户隔离,请在调用前将租户信息注入 context。
ctx := repository.WithTenantContext(ctx, repository.TenantContext{
TenantID: tenantID,
DeptID: deptID,
IsAdmin: false,
})
err := repo.Create(ctx, user)如需对非多租户表关闭强制隔离,实现接口即可:
type NonTenantModel struct {
ID string `gorm:"column:id;type:char(26);primaryKey"`
Name string `gorm:"column:name"`
}
func (NonTenantModel) TenantIgnored() bool { return true }Max/Min/MaxWithCondition/MinWithCondition 的返回值类型由数据库驱动决定(如 int64/float64/string/[]byte/time.Time 等),
无记录时返回 nil。调用方应按实际类型进行断言或转换。
基于 validator/v10 的验证器封装。
import "github.com/aisgo/ais-go-pkg/validator"
type CreateUserRequest struct {
Email string `validate:"required,email"`
Age int `validate:"gte=0,lte=120"`
Username string `validate:"required,min=3,max=20"`
}
v := validator.New()
req := &CreateUserRequest{Email: "invalid", Age: 200}
if err := v.Validate(req); err != nil {
// 处理验证错误
}import (
"github.com/aisgo/ais-go-pkg/validator"
"go.uber.org/fx"
)
app := fx.New(
validator.Module,
fx.Invoke(func(v *validator.Validator) {
// 使用验证器...
}),
)分优先级管理资源清理顺序。
import "github.com/aisgo/ais-go-pkg/shutdown"
manager := shutdown.NewManager(log)
// 注册清理函数(优先级:数字越小越先执行)
manager.Register(shutdown.PriorityHigh, func(ctx context.Context) error {
return httpServer.Shutdown(ctx)
})
manager.Register(shutdown.PriorityMedium, func(ctx context.Context) error {
return db.Close()
})
// 等待信号并执行清理
manager.Wait()import (
"github.com/aisgo/ais-go-pkg/shutdown"
"go.uber.org/fx"
)
app := fx.New(
shutdown.Module,
fx.Invoke(func(manager *shutdown.Manager) {
// 注册清理函数
manager.Register(shutdown.PriorityHigh, func(ctx context.Context) error {
return httpServer.Shutdown(ctx)
})
}),
)- 接口优先 - 所有组件基于接口设计,便于 Mock 和替换
- 配置驱动 - 通过配置文件和环境变量控制行为
- 依赖注入 - 支持 Uber Fx,也可独立使用
- 错误透明 - 统一错误处理和转换机制
- 可观测性 - 内置日志、指标、链路追踪支持
ais-go-pkg/
├── cache/ # 缓存组件
│ └── redis/ # Redis 实现
├── conf/ # 配置加载
├── database/ # 数据库连接
│ └── postgres/ # PostgreSQL 实现
├── errors/ # 错误定义
├── logger/ # 日志组件
├── metrics/ # 监控指标
├── middleware/ # HTTP 中间件
├── mq/ # 消息队列
│ ├── kafka/ # Kafka 适配器
│ └── rocketmq/ # RocketMQ 适配器
├── repository/ # 数据仓储
├── response/ # 响应封装
├── shutdown/ # 优雅关闭
├── transport/ # 传输层
│ ├── http/ # HTTP 服务器
│ └── grpc/ # gRPC 服务器
├── utils/ # 工具函数
└── validator/ # 数据验证
- 在对应目录创建包
- 定义清晰的接口
- 提供配置结构体
- 实现 Fx 模块(可选)
- 编写单元测试
- 更新文档
# 运行所有测试
go test ./...
# 带覆盖率
go test -cover ./...
# 指定包
go test ./logger -v- 遵循 Uber Go Style Guide
- 所有公共 API 必须有注释
- 使用 ASCII 风格分块注释组织代码
- 错误处理必须明确,不吞噬错误
| 库 | 版本 | 用途 |
|---|---|---|
| go.uber.org/zap | v1.27.1 | 结构化日志 |
| go.uber.org/fx | v1.24.0 | 依赖注入 |
| github.com/spf13/viper | v1.21.0 | 配置管理 |
| gorm.io/gorm | v1.31.1 | ORM 框架 |
| github.com/redis/go-redis/v9 | v9.17.2 | Redis 客户端 |
| github.com/gofiber/fiber/v3 | v3.0.0-rc.3 | HTTP 框架 |
| google.golang.org/grpc | v1.78.0 | gRPC 框架 |
| github.com/IBM/sarama | v1.46.3 | Kafka 客户端 |
| github.com/apache/rocketmq-client-go/v2 | v2.1.2 | RocketMQ 客户端 |
| github.com/prometheus/client_golang | v1.23.2 | Prometheus 客户端 |
| github.com/go-playground/validator/v10 | v10.30.1 | 数据验证 |
欢迎提交 Issue 和 Pull Request!
<type>(<scope>): <subject>
<body>
<footer>
Type:
feat: 新功能fix: 修复 Bugdocs: 文档更新refactor: 代码重构test: 测试相关chore: 构建/工具链
MIT License - 详见 LICENSE 文件
- CLAUDE.md - 详细架构文档
- Go 官方文档
- Uber Go Style Guide
Made with ❤️ by AIS Team