322 lines
7.4 KiB
Markdown
322 lines
7.4 KiB
Markdown
# go-web-gin
|
||
|
||
一个基于 [Gin](https://github.com/gin-gonic/gin) 的 Go Web 应用脚手架,提供开箱即用的基础设施组件。
|
||
|
||
## 特性
|
||
|
||
- 🚀 **快速启动** - 简洁的 API 设计,快速搭建 Web 服务
|
||
- 🔧 **配置管理** - 支持 YAML 配置文件和环境变量覆盖
|
||
- 📝 **结构化日志** - 基于 [Zap](https://github.com/uber-go/zap) 的高性能日志
|
||
- 🗄️ **数据库支持** - MySQL (GORM) 和 Redis 单例连接
|
||
- 🌍 **多环境** - 支持 Local、Development、Production 环境
|
||
- 🧩 **单例模式** - 组件单例管理,避免重复初始化
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
go get git.hujye.com/infrastructure/go-web-gin
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 1. 创建配置文件
|
||
|
||
在项目根目录创建 `config/config.yml`:
|
||
|
||
```yaml
|
||
server:
|
||
host: 0.0.0.0
|
||
port: 8080
|
||
mode: debug # debug, release, test
|
||
|
||
app:
|
||
name: my-app
|
||
environment: local
|
||
log_level: info
|
||
|
||
log:
|
||
output_to_file: true
|
||
filename: logs/app.log
|
||
max_size: 100
|
||
max_backups: 3
|
||
max_age: 28
|
||
compress: true
|
||
|
||
mysql:
|
||
host: 127.0.0.1
|
||
port: 3306
|
||
user: root
|
||
password: ""
|
||
db_name: test
|
||
charset: utf8mb4
|
||
parse_time: true
|
||
max_idle_conns: 10
|
||
max_open_conns: 100
|
||
conn_max_lifetime: 3600
|
||
|
||
redis:
|
||
addr: 127.0.0.1:6379
|
||
password: ""
|
||
db: 0
|
||
pool_size: 10
|
||
min_idle_conns: 5
|
||
max_retries: 3
|
||
dial_timeout: 5
|
||
read_timeout: 3
|
||
write_timeout: 3
|
||
```
|
||
|
||
### 2. 编写主程序
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
|
||
go_web_gin "git.hujye.com/infrastructure/go-web-gin"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func main() {
|
||
// 创建应用实例
|
||
app := go_web_gin.New()
|
||
|
||
// 初始化数据库(可选)
|
||
app.InitMySQL()
|
||
app.InitRedis()
|
||
|
||
// 注册全局中间件
|
||
app.UseMiddleware(gin.Recovery())
|
||
|
||
// 注册路由
|
||
app.RegisterRoutes(func(e *gin.Engine) {
|
||
e.GET("/ping", func(c *gin.Context) {
|
||
c.JSON(200, gin.H{"message": "pong"})
|
||
})
|
||
|
||
e.GET("/users/:id", func(c *gin.Context) {
|
||
id := c.Param("id")
|
||
// 使用日志
|
||
app.Logger().Info(c.Request.Context(), "get user", "id", id)
|
||
c.JSON(200, gin.H{"user_id": id})
|
||
})
|
||
|
||
// 使用数据库
|
||
e.GET("/db-test", func(c *gin.Context) {
|
||
db := app.DB()
|
||
if db != nil {
|
||
// 执行数据库操作
|
||
c.JSON(200, gin.H{"db": "connected"})
|
||
} else {
|
||
c.JSON(500, gin.H{"error": "db not initialized"})
|
||
}
|
||
})
|
||
|
||
// 使用 Redis
|
||
e.GET("/redis-test", func(c *gin.Context) {
|
||
rdb := app.Redis()
|
||
if rdb != nil {
|
||
rdb.Set(c.Request.Context(), "test", "value", 0)
|
||
c.JSON(200, gin.H{"redis": "connected"})
|
||
} else {
|
||
c.JSON(500, gin.H{"error": "redis not initialized"})
|
||
}
|
||
})
|
||
})
|
||
|
||
// 启动服务
|
||
// 非生产环境可传入自定义地址,生产环境使用配置文件地址
|
||
app.Run()
|
||
}
|
||
```
|
||
|
||
## API 文档
|
||
|
||
### App 结构
|
||
|
||
```go
|
||
type App struct {
|
||
engine *gin.Engine
|
||
db *gorm.DB
|
||
rdb *redis.Client
|
||
logger *logger.Logger
|
||
}
|
||
```
|
||
|
||
### 方法列表
|
||
|
||
| 方法 | 说明 | 返回值 |
|
||
|------|------|--------|
|
||
| `New()` | 创建新的 App 实例 | `*App` |
|
||
| `UseMiddleware(...)` | 注册全局中间件 | - |
|
||
| `RegisterRoutes(func)` | 注册路由 | - |
|
||
| `InitMySQL()` | 初始化 MySQL 连接 | `*gorm.DB` |
|
||
| `InitRedis()` | 初始化 Redis 连接 | `*redis.Client` |
|
||
| `DB()` | 获取数据库实例 | `*gorm.DB` |
|
||
| `Redis()` | 获取 Redis 实例 | `*redis.Client` |
|
||
| `Logger()` | 获取日志实例 | `*logger.Logger` |
|
||
| `Run(addr ...string)` | 启动服务 | `error` |
|
||
|
||
### Run 方法行为
|
||
|
||
- **非生产环境**:优先使用传入的地址,否则使用配置文件地址
|
||
- **生产环境**:始终使用配置文件地址
|
||
|
||
```go
|
||
// 使用配置文件地址
|
||
app.Run()
|
||
|
||
// 非生产环境使用 :3000,生产环境仍用配置文件地址
|
||
app.Run(":3000")
|
||
```
|
||
|
||
## 环境变量
|
||
|
||
| 变量 | 说明 | 默认值 |
|
||
|------|------|--------|
|
||
| `RUN_ENV` | 运行环境 (`LOCAL`, `DEVELOPMENT`, `PRODUCTION`) | `LOCAL` |
|
||
| `CFG_PATH` | 配置文件路径 | `config/config.yml` |
|
||
|
||
## 日志使用
|
||
|
||
```go
|
||
// 基本用法
|
||
app.Logger().Info(ctx, "message")
|
||
app.Logger().Error(ctx, "error message")
|
||
app.Logger().Warn(ctx, "warning message")
|
||
app.Logger().Debug(ctx, "debug message")
|
||
|
||
// 带键值对
|
||
app.Logger().Info(ctx, "user logged in", "user_id", "123", "ip", "192.168.1.1")
|
||
```
|
||
|
||
日志格式会根据环境自动切换:
|
||
- **Local**: Console 格式,便于阅读
|
||
- **Development/Production**: JSON 格式,便于日志收集
|
||
|
||
## 上下文用户信息
|
||
|
||
使用 `web` 包在上下文中传递用户信息:
|
||
|
||
```go
|
||
import "git.hujye.com/infrastructure/go-web-gin/web"
|
||
|
||
// 设置用户信息
|
||
ctx = web.SetUserID(ctx, "user-123")
|
||
ctx = web.SetUserName(ctx, "john")
|
||
ctx = web.SetTrace(ctx, "trace-456")
|
||
ctx = web.SetFromIP(ctx, "192.168.1.1")
|
||
|
||
// 获取用户信息
|
||
userID := web.GetUserID(ctx)
|
||
userName := web.GetUserName(ctx)
|
||
|
||
// 或一次性构建
|
||
userInfo := web.NewUserInfo().
|
||
WithUserID("user-123").
|
||
WithUserName("john").
|
||
WithTrace("trace-456").
|
||
WithFromIP("192.168.1.1")
|
||
ctx = web.ToContext(ctx, userInfo)
|
||
```
|
||
|
||
日志会自动从上下文中提取用户信息并记录。
|
||
|
||
## 使用 svr 包直接操作 Gin
|
||
|
||
如果需要直接使用 Gin 引擎单例:
|
||
|
||
```go
|
||
import "git.hujye.com/infrastructure/go-web-gin/svr"
|
||
|
||
// 获取引擎
|
||
engine := svr.GetEngine()
|
||
|
||
// 快捷方法
|
||
svr.Use(middleware...)
|
||
svr.GET("/ping", handler)
|
||
svr.POST("/users", handler)
|
||
svr.PUT("/users/:id", handler)
|
||
svr.DELETE("/users/:id", handler)
|
||
|
||
// 路由组
|
||
api := svr.Group("/api/v1")
|
||
api.GET("/users", handler)
|
||
|
||
// 启动服务
|
||
svr.Run(":8080")
|
||
```
|
||
|
||
## 配置读取
|
||
|
||
```go
|
||
import "git.hujye.com/infrastructure/go-web-gin/config"
|
||
|
||
// 获取完整配置
|
||
cfg := config.Get()
|
||
|
||
// 访问配置项
|
||
addr := cfg.GetAddr() // host:port
|
||
isDebug := cfg.IsDebug() // 是否 debug 模式
|
||
isRelease := cfg.IsRelease() // 是否 release 模式
|
||
|
||
// 动态读取配置(支持嵌套键)
|
||
dbHost := config.GetString("mysql.host")
|
||
dbPort := config.GetInt("mysql.port")
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
go-web-gin/
|
||
├── app.go # 应用核心
|
||
├── app_test.go # 测试套件
|
||
├── config/
|
||
│ └── config.go # 配置管理
|
||
├── database/
|
||
│ ├── mysql.go # MySQL 单例
|
||
│ └── redis.go # Redis 单例
|
||
├── env/
|
||
│ └── env.go # 环境变量
|
||
├── logger/
|
||
│ ├── logger.go # 日志核心
|
||
│ ├── encoder.go # 编码器
|
||
│ └── struct.go # 结构定义
|
||
├── server/
|
||
│ └── server.go # 服务器封装
|
||
├── svr/
|
||
│ └── server.go # Gin 单例
|
||
└── web/
|
||
└── user.go # 上下文用户信息
|
||
```
|
||
|
||
## 运行测试
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
go test -v ./...
|
||
|
||
# 运行特定测试套件
|
||
go test -v ./... -run TestAppRunSuite
|
||
```
|
||
|
||
## 依赖
|
||
|
||
- [gin-gonic/gin](https://github.com/gin-gonic/gin) - Web 框架
|
||
- [uber-go/zap](https://github.com/uber-go/zap) - 高性能日志
|
||
- [go-gorm/gorm](https://github.com/go-gorm/gorm) - ORM
|
||
- [redis/go-redis](https://github.com/redis/go-redis) - Redis 客户端
|
||
- [spf13/viper](https://github.com/spf13/viper) - 配置管理
|
||
- [stretchr/testify](https://github.com/stretchr/testify) - 测试框架
|
||
|
||
## License
|
||
|
||
MIT License
|
||
|
||
## Author
|
||
|
||
**hujye**
|
||
|
||
- Email: hujie@hujye.com
|