Skip to content

开发规范

接口与路由

  • 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/authJWT/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认证中间件

基于 MIT 许可发布