Files
go-common/INTEGRATION.md

238 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. 安装
```bash
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`](./config/example.json)。
---
## 3. 推荐结构
```text
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. 启动(只做一次)
```bash
cp templates/server/main.go cmd/server/main.go
```
模板默认已包含:`MustInit` + `buildOptions`Option 挂载点)+ `MustLogger` + `Warmup` + `MiddlewareChain` + `NewHandler` + `Close`
复制后主要改三处:
| 函数 | 用途 |
|------|------|
| `buildOptions()` | `WithLogger` / `WithStorage` 等自定义注入 |
| `setupMiddleware()` | `chain.Append(业务鉴权…)` |
| `registerRoutes()` | 注册业务路由 |
```bash
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` 注入 |
| HTTP 出参 | `NewHandler(w, r)` | `Success` / `Error` / `ErrorData` |
| 中间件 | `MiddlewareChain()` | `Append` / `ThenFunc` |
| 迁移 | `Migrator(dir)` | Up / Down / Status |
| 生命周期 | `Close()` / `Warmup(...)` | 收口 / 启动预热 |
`MustXxx` 仅用于 **main / 启动注入**(失败 panic
```go
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
```json
{ "code": 0, "message": "success", "timestamp": 1704067200, "data": {} }
```
分页 `data``{ "list", "total", "page", "pageSize" }`
```go
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. 数据库迁移
```bash
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。
```sql
-- 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. 模块速查
```go
// 日志
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)
// i18nlocales 目录;出参经 NewHandler 自动用)
app.MustI18n().GetMessage("zh-CN", "user.not_found")
// tools不经 Factory
tools.Now()
tools.MD5("text")
```
---
## 9. 最小 config.json
```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`](./config/example.json)。
---
## 10. 反模式
- Handler 内重复 `Init`
- Service 拼 HTTP JSON / 自定义 Response
- 自行 `gorm.Open` / `redis.NewClient`
- Factory 透传(`LogInfo``Success``Now` 等)
- 请求路径滥用 `MustXxx`
---
## 11. 故障排除
| 问题 | 处理 |
|------|------|
| 无法下载模块 | 检查 `GOPRIVATE` 与 SSH insteadOf |
| 依赖异常 | `go clean -modcache && go mod tidy` |
| getter 报 config is nil | 补配置段,或不调用该模块 |
| 迁移找不到文件 | 检查 `-dir` 与 SQL 命名 |
版本发布见 [VERSION.md](./VERSION.md)。