Skip to content

Repository files navigation

Starter

Go ReferenceGo Report Card

English | 中文

这是 Starter 框架,采用简化架构设计,适合快速开发和简单应用场景。专注于提供轻量级、高效的 Go Web 开发体验。

特征

  • 提供基于 Gin 框架的轻量级项目模板
  • 使用简洁的手动依赖注入,实现清晰的代码结构
  • 采用简化的架构设计,专注于快速开发
  • 集成 GORM 进行 ORM 映射和数据库操作
    • 支持 PostgreSQL (使用 pgx 驱动)
    • 支持 MySQL
    • 支持 SQLite
  • 集成 Viper 进行配置管理
  • 提供常用 Gin 中间件和工具
    • 跨域中间件:处理 API 跨域请求,实现 CORS 支持
    • JWT 解析中间件:从请求中解析并验证 JWT Token,用于 API 身份认证
  • 国际化 (i18n) 支持
    • 基于请求 Accept-Language 头自动选择语言
    • 错误消息多语言支持
  • 使用 Cobra 命令行框架,提供清晰的子命令结构
  • 支持数据库迁移与服务器启动分离,提高启动速度
  • 简化的用户管理系统,使用单一用户表和 IsAdmin 字段区分管理员
  • 优化的错误处理系统,支持错误码和多语言错误消息

架构设计

项目采用简化的架构设计,使用手动依赖注入,实现了清晰的代码结构:

1. 简化的分层架构

  • Model 层:定义数据模型和数据库表结构
  • Handler 层:处理 HTTP 请求和响应,直接与数据库交互
  • Router 层:定义 API 路由,依赖于 Handler 层

2. 依赖注入

项目使用简洁的手动依赖注入,通过构造函数注入依赖:

// Model 层funcNewUserRepo(db*gorm.DB) *UserRepo {
// ...
}
// Handler 层funcNewUserHandler(db*gorm.DB, config*configs.Config) *UserHandler {
// ...
}
// Router 层funcNewRouter(userHandler*handler.UserHandler) *gin.Engine {
// ...
}

3. 应用容器管理

使用应用容器管理组件的生命周期,确保组件的正确初始化和清理:

typeAppstruct {
config*configs.Configdb*gorm.DBhandlers*Handlersrouter*gin.Engineserver*http.Server
}
funcNew(config*configs.Config) (*App, error) {
app:=&App{config: config}
// 按顺序初始化各个组件iferr:=app.initDatabase(); err!=nil {
returnnil, err
}
// ... 其他组件初始化returnapp, nil
}

快速开始

go install github.com/go-eagle/eagle/cmd/eagle@latest
eagle new <project name> -r https://github.com/limitcool/starter

使用方法

应用使用Cobra命令行框架,提供了更清晰的子命令结构。

基本命令

# 查看帮助信息
./<app-name> --help
# 查看版本信息
./<app-name> version
# 启动服务器
./<app-name> server
# 执行数据库迁移
./<app-name> migrate

服务器命令

服务器命令用于启动HTTP服务:

# 使用默认配置启动服务器
./<app-name> server
# 指定端口启动服务器
./<app-name> server --port 9000
# 使用指定配置文件启动服务器
./<app-name> server --config custom.yaml

数据库迁移命令

数据库迁移命令用于初始化或更新数据库结构:

# 执行数据库迁移
./<app-name> migrate
# 使用指定配置文件执行迁移
./<app-name> migrate --config prod.yaml
# 在迁移前清空数据库(危险操作)
./<app-name> migrate --fresh
# 回滚上一批数据库迁移
./<app-name> migrate rollback
# 显示数据库迁移状态
./<app-name> migrate status
# 重置所有数据库迁移
./<app-name> migrate reset

用户管理设计

框架采用简化的用户管理设计,专注于快速开发和简单应用场景:

单一用户表设计

  • 只使用 user 一张表存储所有用户信息
  • 通过 is_admin 字段区分普通用户和管理员用户
  • 简化的数据库结构,减少表之间的关联
  • 使用简化的权限检查中间件,只检查用户是否为管理员

配置管理员用户

在配置文件中设置初始管理员用户:

admin:
username: "admin"password: "admin123"nickname: "超级管理员"

系统会在首次启动时自动创建管理员用户。

数据库迁移系统

框架实现了一个简洁的数据库迁移系统,用于管理数据库表结构的创建和更新。

迁移系统特点

  • 支持按版本号顺序执行迁移
  • 跟踪已执行的迁移记录
  • 支持事务性迁移,确保数据一致性
  • 提供向上和向下迁移功能
  • 支持批次回滚和完全重置

迁移文件结构

迁移定义在 internal/migration/migrations.go 文件中,遵循以下结构:

migrator.Register(&MigrationEntry{
Version: "202504080001", // 版本号格式:年月日序号Name: "create_users_table", // 迁移名称Up: func(tx*gorm.DB) error { // 向上迁移函数returntx.AutoMigrate(&model.User{})
},
Down: func(tx*gorm.DB) error { // 向下迁移函数returntx.Migrator().DropTable("users")
},
})

预定义迁移

框架已预定义了基础的迁移项:

  1. 用户表 (users)
  2. 文件表 (files)

添加新迁移

要添加新的迁移,在 internal/migration/migrations.go 文件中:

  1. 创建新的注册函数或在已有函数中添加
  2. 确保版本号遵循时间戳顺序
  3. 使用 RegisterMigration 函数注册
// 示例:添加新的业务表迁移RegisterMigration("create_products_table",
// 向上迁移函数func(tx*gorm.DB) error {
returntx.AutoMigrate(&model.Product{})
},
// 向下迁移函数func(tx*gorm.DB) error {
returntx.Migrator().DropTable("products")
},
)

迁移记录表

系统通过 migrations 表跟踪迁移的执行状态,包含以下字段:

  • id:自增主键
  • version:迁移版本号(唯一索引)
  • name:迁移名称
  • created_at:执行时间
  • batch:批次号(用于回滚)

环境配置

通过环境变量 APP_ENV 来指定运行环境,或通过 --config 标志直接指定配置文件:

  • APP_ENV=devAPP_ENV=development - 开发环境(默认)
  • APP_ENV=testAPP_ENV=testing - 测试环境
  • APP_ENV=prodAPP_ENV=production - 生产环境

示例:

# 开发环境运行服务器
APP_ENV=dev ./<app-name> server
# 生产环境执行数据库迁移
APP_ENV=prod ./<app-name> migrate

配置文件

配置文件根据运行环境自动加载对应的配置文件:

  • dev.yaml - 开发环境配置
  • test.yaml - 测试环境配置
  • prod.yaml - 生产环境配置
  • example.yaml - 示例配置(用于版本控制)

配置文件可以放置在以下位置(按查找顺序):

  1. 当前工作目录(项目根目录)
  2. configs/ 目录

首次使用时,请复制示例配置并根据环境重命名:

# 开发环境
cp example.yaml dev.yaml
# 测试环境
cp example.yaml test.yaml
# 生产环境
cp example.yaml prod.yaml

应用程序会根据环境变量 APP_ENV 自动寻找并加载对应的配置文件。例如,当 APP_ENV=dev 时,将按以下顺序查找配置文件:

  1. ./dev.yaml(当前目录)
  2. ./configs/dev.yaml(configs目录)

如果找不到对应的配置文件,应用程序将无法启动。

国际化 (i18n) 支持

系统内置了国际化支持,可以根据客户端请求自动切换语言。

配置国际化

在配置文件中设置国际化选项:

I18n:
Enabled: true # 是否启用国际化DefaultLanguage: en-US # 默认语言SupportLanguages: # 支持的语言列表
- zh-CN
- en-USResourcesPath: locales # 语言资源文件路径

语言资源文件

语言资源文件位于 locales 目录下,采用 JSON 格式:

  • locales/en-US.json - 英文资源
  • locales/zh-CN.json - 中文资源

示例语言文件内容:

{
"error.success": "Success",
"error.common.invalid_params": "Invalid request parameters",
"error.user.user_not_found": "User not found"
}

使用方法

  1. API响应自动翻译

    • 系统会自动根据请求头 Accept-Language 选择语言
    • API错误响应会根据设置的语言返回对应的翻译文本
  2. 客户端请求示例

    # 请求英文响应
    curl -X POST "http://localhost:8080/api/v1/user/login" \
    -H "Accept-Language: en-US" \
    -H "Content-Type: application/json" \
    -d '{"username": "test", "password": "wrong"}'# 请求中文响应
    curl -X POST "http://localhost:8080/api/v1/user/login" \
    -H "Accept-Language: zh-CN" \
    -H "Content-Type: application/json" \
    -d '{"username": "test", "password": "wrong"}'
  3. 添加新的错误码翻译

    • tools/errorgen/error_codes.md 中定义错误
    • 运行错误代码生成器: go run tools/errorgen/main.go tools/errorgen/error_codes.md internal/pkg/errorx/code_gen.go
    • 在语言文件 (locales/en-US.jsonlocales/zh-CN.json) 中添加对应的翻译
  4. 添加新的语言支持

    • 创建新的语言文件,如 locales/fr-FR.json
    • 在配置中的 SupportLanguages 列表中添加该语言
    • 重启应用使配置生效

错误处理系统

项目实现了一个完整的错误处理系统,包括错误码、错误包装和多语言错误消息。

错误处理特点

  • 统一的错误码定义和管理
  • 错误包装,保留完整的错误链和堆栈信息
  • 多语言错误消息支持
  • 区分内部错误和用户可见错误

错误处理最佳实践

  • Repository 层:返回具体错误,不记录日志
  • Service 层:包装错误,添加业务上下文,不记录日志
  • Controller 层:转换为用户友好的错误响应,记录完整错误日志

使用示例

// Repository 层func (r*UserRepo) GetByID(ctx context.Context, idint64) (*model.User, error) {
varuser model.Useriferr:=r.DB.First(&user, id).Error; err!=nil {
iferrors.Is(err, gorm.ErrRecordNotFound) {
returnnil, errorx.NewError(errorx.ErrorUserNotFoundCode, "用户不存在")
}
returnnil, err
}
return&user, nil
}
// Service 层func (s*UserService) GetUserByID(ctx context.Context, idint64) (*model.User, error) {
user, err:=s.userRepo.GetByID(ctx, id)
iferr!=nil {
returnnil, errorx.WrapError(err, fmt.Sprintf("获取用户ID %d 失败", id))
}
returnuser, nil
}
// Controller 层func (c*UserController) GetUser(ctx*gin.Context) {
id:=cast.ToInt64(ctx.Param("id"))
user, err:=c.userService.GetUserByID(ctx, id)
iferr!=nil {
logger.Error("获取用户失败", "error", err, "id", id)
response.Error(ctx, err)
return
}
response.Success(ctx, user)
}

日志配置

项目使用 uber-go/zap 作为日志库,提供高性能的结构化日志记录。

配置示例

Log:
Level: info # 日志级别: debug, info, warn, errorOutput: [console, file] # 输出方式: console, fileFormat: text # 日志格式: text, jsonStackTraceEnabled: true # 是否启用堆栈跟踪StackTraceLevel: error # 堆栈跟踪级别: error, warn, info, debugMaxStackFrames: 20# 最大堆栈帧数FileConfig:
Path: ./logs/app.log # 日志文件路径MaxSize: 100# 每个日志文件的最大大小(MB)MaxAge: 7# 日志文件保留天数MaxBackups: 10# 保留的旧日志文件最大数量Compress: true # 是否压缩旧日志文件

日志级别

  • debug: 调试信息,包含详细的开发调试信息
  • info: 一般信息,默认级别
  • warn: 警告信息,需要注意的信息
  • error: 错误信息,影响程序正常运行的错误

日志格式

  • text: 普通文本格式,适合人类阅读(默认)
  • json: JSON结构化格式,适合机器解析和日志系统收集

输出方式

  • console: 输出到控制台,支持彩色输出
  • file: 输出到文件,支持按大小自动分割、自动清理和压缩

可以同时配置多个输出方式,日志会同时输出到所有配置的目标。如果不配置 output,默认只输出到控制台。

堆栈跟踪配置

  • StackTraceEnabled: 是否启用堆栈跟踪,默认为 true
  • StackTraceLevel: 堆栈跟踪级别,默认为 error,只有该级别及以上的日志才会记录堆栈
  • MaxStackFrames: 最大堆栈帧数,默认为 20

文件输出配置

  • Path: 日志文件路径
  • MaxSize: 单个日志文件的最大大小(MB),超过后会自动分割
  • MaxAge: 日志文件保留天数,超过后会自动删除
  • MaxBackups: 保留的旧日志文件数量
  • Compress: 是否压缩旧的日志文件

使用示例

日志库提供了统一的接口:

// 导入日志包import"github.com/limitcool/starter/internal/pkg/logger"// 记录不同级别的日志funcexample() {
// 记录信息日志logger.Info("This is an info message", "user", "admin", "action", "login")
// 记录警告日志logger.Warn("This is a warning message", "memory", "90%")
// 记录错误日志err:=someFunction()
iferr!=nil {
logger.Error("Operation failed", "error", err, "operation", "someFunction")
}
// 记录错误日志,并包含堆栈信息iferr!=nil {
logger.LogErrorWithStack("Operation failed with stack", err, "operation", "someFunction")
}
// 记录调试日志logger.Debug("Detailed debug information", "request", req, "response", resp)
}

性能分析 (Pprof) 支持

项目内置了 Go 官方的 pprof 性能分析工具,可以帮助开发者分析应用的性能瓶颈。

配置示例

Pprof:
Enabled: true # 是否启用pprofPort: 0# pprof服务端口,0表示使用主服务端口

配置说明

  • Enabled: 是否启用pprof功能,生产环境建议设为false
  • Port: pprof服务端口
    • 0: 在主HTTP服务器上启用pprof路由 (推荐开发环境)
    • 6060: 启动独立的pprof服务器 (推荐生产环境调试)

使用方法

1. 主服务器模式 (Port: 0)

当配置 Port: 0 时,pprof路由会添加到主HTTP服务器:

# 启动应用
./starter server
# 访问pprof主页
curl http://localhost:8080/debug/pprof/
# 查看goroutine信息
curl http://localhost:8080/debug/pprof/goroutine?debug=1
# 获取CPU profile (30秒)
curl http://localhost:8080/debug/pprof/profile?seconds=30 > cpu.prof
# 查看内存heap信息
curl http://localhost:8080/debug/pprof/heap?debug=1

2. 独立服务器模式 (Port: 6060)

当配置具体端口时,会启动独立的pprof服务器:

Pprof:
Enabled: truePort: 6060
# 启动应用
./starter server
# 访问独立pprof服务器
curl http://localhost:6060/debug/pprof/
# 使用go tool pprof分析
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
go tool pprof http://localhost:6060/debug/pprof/heap

常用pprof端点

  • /debug/pprof/ - pprof主页,显示所有可用的profile
  • /debug/pprof/goroutine - 查看所有goroutine的堆栈信息
  • /debug/pprof/heap - 查看内存分配信息
  • /debug/pprof/profile - CPU性能分析 (默认30秒)
  • /debug/pprof/block - 查看阻塞操作的堆栈信息
  • /debug/pprof/mutex - 查看互斥锁竞争信息
  • /debug/pprof/allocs - 查看内存分配采样信息
  • /debug/pprof/threadcreate - 查看线程创建信息

安全建议

  • 开发环境: 可以使用主服务器模式 (Port: 0),方便调试
  • 生产环境: 建议禁用pprof (Enabled: false) 或使用独立端口并限制访问
  • 调试生产问题: 临时启用独立端口模式,调试完成后立即禁用

gRPC 支持

项目集成了 gRPC 支持,可与 HTTP 服务并行运行,提供高性能的 RPC 服务。

gRPC 特点

  • 可通过配置启用/禁用 gRPC 服务
  • 支持 gRPC 健康检查和反射服务
  • 与 HTTP 服务共享业务逻辑
  • 使用 Protocol Buffers 定义 API

配置示例

GRPC:
Enabled: true # 是否启用 gRPC 服务Port: 9000# gRPC 服务端口HealthCheck: true # 是否启用健康检查服务Reflection: true # 是否启用反射服务

使用方法

  1. 定义 Proto 文件

    Proto 文件定义在 internal/proto/v1 目录下,生成的代码在 internal/proto/gen/v1 目录下。

    // internal/proto/v1/system.protosyntax="proto3";
    packageinternal.proto.v1;
    optiongo_package="internal/proto/gen/v1;protov1";
    // SystemService 系统服务serviceSystemService {
    // GetSystemInfo 获取系统信息rpcGetSystemInfo(SystemInfoRequest) returns (SystemInfoResponse) {}
    }
    // SystemInfoRequest 系统信息请求messageSystemInfoRequest {
    // 请求IDstringrequest_id=1;
    }
    // SystemInfoResponse 系统信息响应messageSystemInfoResponse {
    // 应用名称stringapp_name=1;
    // 应用版本stringversion=2;
    // 运行模式stringmode=3;
    // 服务器时间int64server_time=4;
    }
  2. 生成 gRPC 代码

    使用 Makefile 中的 proto 命令生成 gRPC 代码:

    make proto
  3. 实现 gRPC 控制器

    internal/controller 目录下创建 gRPC 控制器,使用 _grpc 后缀区分:

    // internal/controller/system_grpc.gopackage controller
    import (
    "context""time"
    pb "github.com/limitcool/starter/internal/proto/gen/v1"// ...
    )
    // SystemGRPCController gRPC系统控制器typeSystemGRPCControllerstruct {
    pb.UnimplementedSystemServiceServer// ...
    }
    // GetSystemInfo 获取系统信息func (c*SystemGRPCController) GetSystemInfo(ctx context.Context, req*pb.SystemInfoRequest) (*pb.SystemInfoResponse, error) {
    // 实现业务逻辑return&pb.SystemInfoResponse{
    AppName: c.config.App.Name,
    Version: "1.0.0",
    Mode: c.config.App.Mode,
    ServerTime: time.Now().Unix(),
    }, nil
    }
  4. 注册 gRPC 服务

    在应用容器中注册 gRPC 控制器:

    // 在应用容器中初始化 gRPC 服务func (a*App) initGRPCServer() error {
    // 创建 gRPC 服务器grpcServer:=grpc.NewServer()
    // 注册服务systemController:=NewSystemGRPCController(a.config)
    pb.RegisterSystemServiceServer(grpcServer, systemController)
    a.grpcServer=grpcServerreturnnil
    }
  5. 使用 gRPC 客户端

    // 创建 gRPC 连接conn, err:=grpc.Dial("localhost:9000", grpc.WithInsecure())
    iferr!=nil {
    log.Fatalf("Failed to connect: %v", err)
    }
    deferconn.Close()
    // 创建客户端client:=pb.NewSystemServiceClient(conn)
    // 调用服务resp, err:=client.GetSystemInfo(context.Background(), &pb.SystemInfoRequest{
    RequestId: "test-request",
    })

权限系统

框架采用简化的权限系统,基于用户的 is_admin 字段进行权限控制:

权限控制中间件

项目提供了三种权限控制中间件:

  1. AdminCheck:检查用户是否为管理员

    • 基于 JWT 中的 is_admin 字段进行快速检查
    • 适用于管理员专属接口
  2. UserCheck:检查用户是否已登录

    • 只验证用户是否登录,不检查用户类型
    • 适用于需要登录但不限制用户类型的接口
  3. RegularUserCheck:检查用户是否为普通用户

    • 确保用户不是管理员
    • 适用于只允许普通用户访问的接口

使用方法

在路由定义中使用中间件:

// 管理员接口adminGroup:=router.Group("/api/v1/admin")
adminGroup.Use(middleware.AdminCheck())
{
adminGroup.GET("/users", handler.ListUsers)
// 其他管理员接口...
}
// 普通用户接口userGroup:=router.Group("/api/v1/user")
userGroup.Use(middleware.UserCheck())
{
userGroup.GET("/profile", handler.GetUserProfile)
// 其他用户接口...
}
// 仅普通用户接口regularUserGroup:=router.Group("/api/v1/regular")
regularUserGroup.Use(middleware.RegularUserCheck())
{
regularUserGroup.POST("/feedback", handler.SubmitFeedback)
// 其他仅普通用户接口...
}

数据库操作

框架采用简化的数据库操作方式,直接在 Model 层提供数据库操作方法:

Model 层设计

在框架中,Model 层直接提供数据库操作方法,简化了代码结构:

// User 用户模型typeUserstruct {
IDuint`gorm:"primarykey" json:"id"`Usernamestring`gorm:"size:50;not null;uniqueIndex" json:"username"`Passwordstring`gorm:"size:100;not null" json:"-"`Nicknamestring`gorm:"size:50" json:"nickname"`Emailstring`gorm:"size:100" json:"email"`Avatarstring`gorm:"size:255" json:"avatar"`IsAdminbool`gorm:"default:false" json:"is_admin"`CreatedAt time.Time`json:"created_at"`UpdatedAt time.Time`json:"updated_at"`
}
// UserRepo 用户数据库操作typeUserRepostruct {
DB*gorm.DB
}
// NewUserRepo 创建用户仓库funcNewUserRepo(db*gorm.DB) *UserRepo {
return&UserRepo{DB: db}
}
// GetByID 根据ID获取用户func (r*UserRepo) GetByID(ctx context.Context, iduint) (*User, error) {
varuserUseriferr:=r.DB.First(&user, id).Error; err!=nil {
iferrors.Is(err, gorm.ErrRecordNotFound) {
returnnil, errorx.ErrUserNotFound
}
returnnil, err
}
return&user, nil
}
// GetByUsername 根据用户名获取用户func (r*UserRepo) GetByUsername(ctx context.Context, usernamestring) (*User, error) {
varuserUseriferr:=r.DB.Where("username = ?", username).First(&user).Error; err!=nil {
iferrors.Is(err, gorm.ErrRecordNotFound) {
returnnil, errorx.ErrUserNotFound
}
returnnil, err
}
return&user, nil
}
// Create 创建用户func (r*UserRepo) Create(ctx context.Context, user*User) error {
returnr.DB.Create(user).Error
}
// Update 更新用户func (r*UserRepo) Update(ctx context.Context, user*User) error {
returnr.DB.Save(user).Error
}
// Delete 删除用户func (r*UserRepo) Delete(ctx context.Context, iduint) error {
returnr.DB.Delete(&User{}, id).Error
}
// List 获取用户列表func (r*UserRepo) List(ctx context.Context, page, pageSizeint) ([]User, int64, error) {
varusers []Uservartotalint64r.DB.Model(&User{}).Count(&total)
offset:= (page-1) *pageSizeiferr:=r.DB.Offset(offset).Limit(pageSize).Find(&users).Error; err!=nil {
returnnil, 0, err
}
returnusers, total, nil
}

在 Handler 中使用

在 Handler 层直接使用 Model 层提供的方法:

// UserHandler 用户处理器typeUserHandlerstruct {
userRepo*model.UserRepoconfig*configs.Config
}
// NewUserHandler 创建用户处理器funcNewUserHandler(userRepo*model.UserRepo, config*configs.Config) *UserHandler {
return&UserHandler{
userRepo: userRepo,
config: config,
}
}
// GetUser 获取用户信息func (h*UserHandler) GetUser(c*gin.Context) {
id:=cast.ToUint(c.Param("id"))
user, err:=h.userRepo.GetByID(c.Request.Context(), id)
iferr!=nil {
response.Error(c, err)
return
}
response.Success(c, user)
}

错误处理

框架提供了简洁而强大的错误处理系统,支持错误码和多语言错误消息。

错误处理特点

  • 统一的错误码定义和管理
  • 错误包装,保留完整的错误链
  • 多语言错误消息支持
  • 区分内部错误和用户可见错误

错误定义

错误定义在 internal/pkg/errorx 包中:

// 错误码定义const (
// 通用错误码ErrorSuccess=0// 成功ErrorUnknown=1000// 未知错误ErrorInvalidParams=1001// 无效参数ErrorNotFound=1002// 资源不存在ErrorDatabase=1003// 数据库错误// 用户相关错误码ErrorUserNotFound=2000// 用户不存在ErrorUserAlreadyExist=2001// 用户已存在ErrorUserAuthFailed=2002// 用户认证失败ErrorUserNoLogin=2003// 用户未登录ErrorAccessDenied=2004// 访问被拒绝
)
// Error 自定义错误类型typeErrorstruct {
Codeint// 错误码Messagestring// 错误消息Errerror// 原始错误
}
// NewError 创建新错误funcNewError(codeint, msgstring) *Error {
return&Error{
Code: code,
Message: msg,
}
}
// WithMsg 设置错误消息func (e*Error) WithMsg(msgstring) *Error {
return&Error{
Code: e.Code,
Message: msg,
Err: e.Err,
}
}
// WithError 包装原始错误func (e*Error) WithError(errerror) *Error {
return&Error{
Code: e.Code,
Message: e.Message,
Err: err,
}
}

使用示例

// 在 Model 层func (r*UserRepo) GetByID(ctx context.Context, iduint) (*User, error) {
varuserUseriferr:=r.DB.First(&user, id).Error; err!=nil {
iferrors.Is(err, gorm.ErrRecordNotFound) {
returnnil, errorx.NewError(errorx.ErrorUserNotFound, "用户不存在")
}
returnnil, errorx.NewError(errorx.ErrorDatabase, "数据库错误").WithError(err)
}
return&user, nil
}
// 在 Handler 层func (h*UserHandler) GetUser(c*gin.Context) {
id:=cast.ToUint(c.Param("id"))
user, err:=h.userRepo.GetByID(c.Request.Context(), id)
iferr!=nil {
logger.Error("获取用户失败", "error", err, "id", id)
response.Error(c, err)
return
}
response.Success(c, user)
}

统一响应格式

所有 API 响应使用统一的格式:

// 成功响应
{
"code": 0,
"message": "success",
"data": {
// 响应数据
}
}
// 错误响应
{
"code": 1001,
"message": "无效参数",
"data": null
}

About

starter 是一个 Go + gin 框架的项目脚手架,提供开箱即用的工具、库和 gin 项目配置,帮助您快速启动 gin 驱动的 API 项目开发。

Topics

Resources

Stars

26 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages