Files
go-web-gin/README.md

322 lines
7.4 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.
# 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