开发规范
接口与路由
- API 前缀:
/api/v1 - Swagger:
/swagger/index.html
工程结构
以 Go 社区工程布局为参考,业务代码集中在:
youlai-gin/
├── main.go # 启动入口
├── configs/ # 环境配置
│ ├── dev.yaml
│ ├── test.yaml
│ └── prod.yaml
├── internal/ # 业务代码
│ ├── auth/ # 认证模块
│ ├── system/ # 系统模块(用户/角色/菜单等)
│ ├── platform/ # 平台服务(文件上传等)
│ ├── health/ # 健康检查
│ └── router/ # 路由注册
├── pkg/ # 可复用基础设施
│ ├── middleware/ # 中间件(鉴权/限流等)
│ ├── auth/ # 认证工具
│ ├── config/ # 配置加载
│ ├── database/ # 数据库连接
│ ├── redis/ # Redis 连接
│ ├── logger/ # 日志
│ └── response/ # 统一响应
├── scripts/ # 数据库脚本
│ └── mysql/
├── go.mod # 依赖管理
└── Dockerfile # 容器构建目录约定
| 目录 | 说明 |
|---|---|
internal/auth | 认证模块(登录/Token/会话) |
internal/system | 系统管理(用户/角色/菜单/部门/字典) |
internal/platform | 平台服务(文件上传等) |
internal/health | 健康检查接口 |
internal/router | 路由注册 |
pkg/middleware | 通用中间件(鉴权/数据权限/限流) |
pkg/auth | JWT/Redis Token 认证 |
pkg/response | 统一响应结构 |
pkg/logger | 日志组件 |
pkg/config | 配置加载 |
命名规范
文件命名
- 全小写,使用下划线分隔:
user_handler.go - 测试文件:
user_handler_test.go
包命名
- 全小写,简短有意义:
middleware,auth,response
函数命名
- 导出函数:大驼峰
GetUserByID - 私有函数:小驼峰
getUserById
常量命名
go
// 错误码常量
const (
CodeSuccess = "00000"
CodeUnauthorized = "A0001"
CodeAccessTokenExpired = "A0230"
)
// Redis Key 常量
const (
RedisUserToken = "auth:user:token:{}"
RedisUserPerms = "auth:user:perms:{}"
)参数校验
推荐使用 go-playground/validator 进行参数校验:
go
type LoginForm struct {
Username string `json:"username" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6,max=20"`
}
func (h *AuthHandler) Login(c *gin.Context) {
var form LoginForm
if err := c.ShouldBindJSON(&form); err != nil {
response.FromError(c, err)
return
}
// 业务处理...
}统一响应
所有接口返回统一格式:
go
type Result struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}成功响应:
go
response.Success(c, data)
// {"code":"00000","msg":"操作成功","data":{...}}错误响应:
go
response.Fail(c, "A0001", "认证失败")
// {"code":"A0001","msg":"认证失败","data":null}错误处理
自定义错误
go
type AppError struct {
Code string
Msg string
HTTPStatus int
}
func (e *AppError) Error() string {
return e.Msg
}错误码规范
| 前缀 | 说明 | 示例 |
|---|---|---|
A0 | 用户端错误 | A0001 认证失败 |
A02 | 认证错误 | A0230 Token 过期 |
A05 | 限流错误 | A0502 并发超限 |
B0 | 系统端错误 | B0001 系统异常 |
接口幂等
- 优先使用数据库唯一约束兜底
- 对高风险写操作使用 Redis 分布式锁
go
// 分布式锁示例
key := fmt.Sprintf("lock:order:%d", orderId)
if !redis.Lock(key, 30*time.Second) {
return errors.New("操作进行中,请勿重复提交")
}
defer redis.Unlock(key)数据库操作
GORM 使用
go
// 查询单条
var user model.User
db.Where("id = ?", userId).First(&user)
// 查询列表
var users []model.User
db.Where("status = ?", 1).Find(&users)
// 分页查询
var total int64
db.Model(&model.User{}).Count(&total)
db.Limit(pageSize).Offset((pageNum-1)*pageSize).Find(&users)事务处理
go
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Create(&userRole).Error; err != nil {
return err
}
return nil
})日志规范
go
import "youlai-gin/pkg/logger"
// 使用结构化日志
logger.Info("用户登录成功",
zap.String("username", username),
zap.String("ip", c.ClientIP()),
)
// 错误日志
logger.Error("订单创建失败",
zap.Int64("orderId", orderId),
zap.Error(err),
)相关文件
| 文件 | 说明 |
|---|---|
pkg/response/result.go | 统一响应结构 |
pkg/errs/error.go | 错误定义 |
pkg/constant/code.go | 错误码常量 |
pkg/middleware/auth.go | 认证中间件 |
