7.4 KiB
GoCommon 业务项目对接手册
模块路径:git.toowon.com/jimmy/go-common
目标架构一步到位,不考虑向后兼容。
1. 原则
| 原则 | 说明 |
|---|---|
| Factory 只是入口 | 启动初始化一次,getter 取模块对象 |
| 能力在模块自身 | log.Info()、db.Find()、store.Upload(),不在 Factory 透传 |
| 按需配置 | 只用到的模块写进 config.json |
| 不重写基础设施 | 连接池、HTTP 出参、中间件链由本库提供 |
| 业务只管业务 | Service 返回数据;出参用 http.Handler;迁移只写 SQL |
登录鉴权、参数校验、出站 HTTP Client 等由业务项目自行实现,不在本库范围。
2. 安装
go env -w GOPRIVATE=git.toowon.com
go env -w GONOPROXY=git.toowon.com
go env -w GONOSUMDB=git.toowon.com
git config --global url."git@git.toowon.com:".insteadOf "https://git.toowon.com/"
go get git.toowon.com/jimmy/go-common@v1.2.0
配置示例:config/example.json。
3. 推荐结构
your-project/
├── config.json
├── cmd/server/main.go # 复制 templates/server/main.go
├── cmd/migrate/main.go # 复制 templates/migrate/main.go
├── migrations/
├── locales/ # 可选
├── internal/handler/
├── internal/service/
└── go.mod
4. 启动(只做一次)
cp templates/server/main.go cmd/server/main.go
模板默认已包含:MustInit + buildOptions(Option 挂载点)+ MustLogger + Warmup + MiddlewareChain + NewHandler + Close。
复制后主要改三处:
| 函数 | 用途 |
|---|---|
buildOptions() |
WithLogger / WithStorage 等自定义注入 |
setupMiddleware() |
chain.Append(业务鉴权…) |
registerRoutes() |
注册业务路由 |
go run ./cmd/server -config config.json -addr :8080
5. 获取模块对象
连接由 Factory lazy 缓存。业务侧不要自行 gorm.Open / redis.NewClient。
| 模块 | API | 说明 |
|---|---|---|
| 配置 | Config() |
原始配置 |
| 数据库 | Database() / MustDatabase() |
*gorm.DB |
| Redis | Redis() / MustRedis() |
*redis.Client |
| 日志 | Logger() / MustLogger() |
退出用 Close() |
| 存储 | Storage() / MustStorage() |
Upload / GetURL |
| 邮件 | Email() / MustEmail() |
SendEmail / SendEmailAsync |
| 短信 | SMS() / MustSMS() |
SendSMS / SendSMSAsync |
| Excel | Excel() |
每次新建导出器 |
| 国际化 | I18n() / MustI18n() |
一般由 NewHandler 注入 |
| MCP 工具 | MCP() / MustMCP() |
ListTools / CallTool(见 §8) |
| HTTP 出参 | NewHandler(w, r) |
Success / Error / ErrorData |
| 中间件 | MiddlewareChain() |
Append / ThenFunc |
| 迁移 | Migrator(dir) |
Up / Down / Status |
| 生命周期 | Close() / Warmup(...) |
收口 / 启动预热 |
MustXxx 仅用于 main / 启动注入(失败 panic)。
func NewUserService(app *factory.Factory) *UserService {
return &UserService{db: app.MustDatabase(), rds: app.MustRedis()}
}
6. HTTP 统一出参
| 层级 | 职责 |
|---|---|
| Service | 返回数据或 error |
| Handler | 解析、调 Service、h.Success / h.Error |
http.Handler |
统一 JSON 信封、i18n、timestamp |
响应格式(HTTP 恒 200):
{ "code": 0, "message": "success", "timestamp": 1704067200, "data": {} }
分页 data:{ "list", "total", "page", "pageSize" }。
h := app.NewHandler(w, r) // 自动注入已配置的 i18n
var req ListUserRequest
if err := h.ParseJSON(&req); err != nil {
h.Error("common.invalid_request")
return
}
users, total, err := svc.List(h.Pagination().GetPage(), h.Pagination().GetPageSize())
if err != nil {
h.Error("user.list_failed")
return
}
h.SuccessPage(users, total)
请求头:Accept-Language(语种)、X-Timezone(默认 Asia/Shanghai)。
7. 数据库迁移
cp templates/migrate/main.go cmd/migrate/main.go
go build -o bin/migrate cmd/migrate/main.go
./bin/migrate up|status|down
模板默认走 Factory:MustInit + 日志 + Warmup(Database) + Migrator + Close;同样可用 buildOptions() 注入自定义 DB/Logger。
-- migrations/20240101000001_create_users.sql
CREATE TABLE users (id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(255) NOT NULL);
-- migrations/20240101000001_create_users.down.sql
DROP TABLE IF EXISTS users;
8. 模块速查
// 日志
app.MustLogger().Info("服务启动", nil)
// 存储
store, _ := app.Storage()
_ = store.Upload(ctx, "images/a.jpg", reader, "image/jpeg")
// 邮件 / 短信(HTTP 通知用 Async;验证码用同步)
app.MustEmail().SendEmailAsync(ctx, []string{"a@b.com"}, "主题", "正文")
app.MustSMS().SendSMSAsync(ctx, []string{"13800138000"}, map[string]string{"code": "123456"})
// Excel
app.Excel().ExportToFile("users.xlsx", "用户列表", columns, users)
// i18n(locales 目录;出参经 NewHandler 自动用)
app.MustI18n().GetMessage("zh-CN", "user.not_found")
// tools(不经 Factory)
tools.Now()
tools.MD5("text")
MCP 工具(Model Context Protocol)Client
本库只做 MCP Client:按配置连接外部 MCP server(容器/服务),发现工具、调用工具; 不含路由/抽参/编排逻辑——用哪个工具、怎么填参数、怎么组合答复,属于业务侧的 Prompt/Agent 编排,需要业务项目自行实现(可参考已有 RAG 项目里的 ToolOrchestrator 写法)。
m := app.MustMCP() // config.mcp 未配置或 enabled=false 时 m.Enabled() 为 false
tools, _ := m.ListTools(ctx) // 聚合全部已启用 server 的工具;FQName = "{toolNamePrefix}__{原始工具名}"
res, _ := m.CallTool(ctx, "word__create_document", map[string]any{"title": "周报"})
// 可选:把 HTTP 层的 request id 传入,调用日志会附带该字段(不传不影响功能)
ctx = mcp.WithRequestID(ctx, requestID)
config.json 中 mcp.servers[] 一条 = 一个独立 MCP server(自带多个工具),新增能力 =
加一条配置,不改代码;allowedTools 留空表示开放该 server 全部工具。完整字段见
config/example.json 的 mcp 段。
9. 最小 config.json
{
"database": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"user": "root",
"password": "password",
"database": "mydb"
},
"logger": {
"level": "info",
"output": "both",
"filePath": "./logs/app.log",
"async": true
},
"i18n": {
"defaultLang": "zh-CN",
"localesDir": "locales"
}
}
完整字段见 config/example.json。
10. 反模式
- Handler 内重复
Init - Service 拼 HTTP JSON / 自定义 Response
- 自行
gorm.Open/redis.NewClient - Factory 透传(
LogInfo、Success、Now等) - 请求路径滥用
MustXxx - 把 MCP 工具路由/抽参/Prompt 编排逻辑塞进本库(应在业务侧基于
mcp.Manager自行实现)
11. 故障排除
| 问题 | 处理 |
|---|---|
| 无法下载模块 | 检查 GOPRIVATE 与 SSH insteadOf |
| 依赖异常 | go clean -modcache && go mod tidy |
| getter 报 config is nil | 补配置段,或不调用该模块 |
| 迁移找不到文件 | 检查 -dir 与 SQL 命名 |
版本发布见 VERSION.md。