工程化目录

三种主流目录结构,按项目规模选。

模板1:简单三层(小项目)

project/
├── main.go                     # 入口:初始化 DB、注册路由
├── handler/                    # 路由层:解析参数 → 调 service → 返回响应
│   ├── user_handler.go
│   └── post_handler.go
├── service/                    # 业务层:核心业务逻辑
│   ├── user_service.go
│   └── post_service.go
├── repository/                 # 数据层:数据库 CRUD
│   ├── user_repository.go
│   └── post_repository.go
├── model/                      # 数据模型(对应数据库表)
│   ├── user.go
│   └── post.go
├── middleware/                 # 中间件
│   ├── auth.go                 #   JWT 鉴权
│   └── cors.go                 #   跨域
├── config/
│   └── config.go               # 读取配置
├── config.yaml                 # 配置文件
├── go.mod
└── go.sum

模板2:企业级分层(团队协作推荐)

myapp/
├── cmd/                            # 程序入口(可有多入口)
│   └── server/
│       └── main.go                 #   只做:装配依赖 → 启动服务

├── internal/                       # 应用私有代码(Go 编译器禁止外部 import)
│   ├── handler/                    # 路由层:解析参数 → 调 service → 返回响应
│   │   ├── user_handler.go
│   │   └── auth_handler.go
│   │
│   ├── service/                    # 业务层:核心业务逻辑
│   │   ├── user_service.go
│   │   └── auth_service.go
│   │
│   ├── repository/                 # 数据层:数据库 CRUD
│   │   ├── user_repository.go
│   │   └── post_repository.go
│   │
│   ├── model/                      # 数据模型(对应数据库表)
│   │   ├── user.go
│   │   └── base.go                 #   公共字段:ID/CreatedAt/UpdatedAt
│   │
│   ├── dto/                        # Data Transfer Object(数据传输对象)
│   │   ├── request/                #   入参结构体(带 binding 校验标签)
│   │   │   ├── user_request.go
│   │   │   └── common_request.go   #     分页等公共请求
│   │   └── response/               #   出参结构体(带 json 标签)
│   │       ├── user_response.go
│   │       └── common_response.go  #     统一响应格式
│   │
│   ├── middleware/                 # 中间件
│   │   ├── auth.go                 #   JWT 认证
│   │   ├── cors.go                 #   跨域
│   │   ├── logger.go               #   请求日志
│   │   ├── recovery.go             #   panic 恢复
│   │   ├── rate_limit.go           #   限流
│   │   └── permission.go           #   权限校验
│   │
│   └── router/                     # 路由注册
│       ├── router.go               #   主路由 + 路由分组
│       └── api_v1.go               #   v1 版本接口

├── pkg/                            # 可被外部项目复用的公共库
│   ├── jwt/                        #   JWT 签发/解析
│   ├── logger/                     #   日志封装(zap 等)
│   ├── database/                   #   数据库连接初始化
│   ├── redis/                      #   Redis 连接
│   ├── response/                   #   统一响应封装
│   └── utils/                      #   通用工具函数

├── config/                         # 配置
│   ├── config.go                   #   配置结构体定义 + 加载逻辑
│   ├── config.yaml                 #   本地开发
│   ├── config.prod.yaml            #   生产环境
│   └── config.test.yaml            #   测试环境

├── migrations/                     # 数据库迁移(SQL 文件,配合 goose/migrate)
│   ├── 000001_create_users.up.sql
│   └── 000001_create_users.down.sql

├── api/                            # API 定义(Swagger / Protobuf)
│   └── swagger.yaml

├── deployments/                    # 部署相关
│   ├── docker/
│   │   └── Dockerfile
│   ├── kubernetes/
│   │   ├── deployment.yaml
│   │   └── service.yaml
│   └── docker-compose.yaml         #   本地起 MySQL+Redis+应用

├── scripts/                        # 运维脚本
│   ├── build.sh
│   └── deploy.sh

├── logs/                           # 日志输出(gitignore)
├── .env.example                    # 环境变量样例(提交到 git)
├── .env                            # 真实环境变量(gitignore)
├── .gitignore
├── Makefile                        # make run / make build / make test
├── go.mod
├── go.sum
└── README.md

模板3:按业务模块聚合(改一个功能只动一个目录)

跟模板2「按层切分」相反:一个业务的 handler/service/repository/model/dto 全放一起,做成自包含模块。改用户功能只在 user/ 目录里跳,不用满项目翻。

myapp/
├── cmd/
│   └── server/
│       └── main.go                 # 入口:装配依赖、启动服务

├── internal/
│   ├── module/                     # 按业务模块聚合(每个模块自包含)
│   │   ├── user/                   # 用户模块:user 相关代码全在这
│   │   │   ├── handler.go          #   路由处理:解析参数 → 调 service → 返回响应
│   │   │   ├── service.go          #   业务逻辑
│   │   │   ├── repository.go       #   数据库 CRUD
│   │   │   ├── model.go            #   数据模型(对应表)
│   │   │   └── dto.go              #   请求/响应结构(带 binding/json 标签)
│   │   └── post/                   # 帖子模块(结构同上)
│   │       ├── handler.go
│   │       ├── service.go
│   │       ├── repository.go
│   │       ├── model.go
│   │       └── dto.go
│   │
│   ├── router/                     # 路由注册:把 URL 绑到各模块 handler
│   │   └── router.go
│   └── middleware/                 # 公共中间件(跨模块复用)
│       ├── auth.go
│       └── cors.go

├── pkg/                            # 公共库(日志、DB 连接、统一响应等,无业务)
├── config/
│   └── config.yaml
├── go.mod
└── go.sum

调用链路:请求 → router → module/user/handler → service → repository → DB

模板4:enter.go 入口聚合(中大型项目)

基于模板2 的分层,每个层目录加一个 enter.go 作为该层统一入口,按业务域(system / example 等)分子目录。新增功能不用改 main.go,只在自己的业务域里注册。

myapp/
├── main.go                         # 入口:调 initialize.InitApp() 完成所有装配

├── api/                            # 路由处理层
│   └── v1/                         #   接口版本
│       ├── enter.go                #   【入口】聚合所有业务域的 handler 集合 ApiGroup
│       ├── system/                 #   系统域
│       │   ├── enter.go            #     聚合 sys_user、sys_menu 等 handler
│       │   ├── sys_user.go
│       │   └── sys_menu.go
│       └── example/                #   业务域(按业务拆)
│           ├── enter.go
│           └── exa_customer.go

├── service/                        # 业务逻辑层(结构同 api,按域聚合)
│   ├── enter.go                    #   【入口】聚合所有业务域的 service 集合
│   ├── system/
│   │   ├── enter.go
│   │   ├── sys_user.go
│   │   └── sys_menu.go
│   └── example/
│       ├── enter.go
│       └── exa_customer.go

├── router/                         # 路由层(按域拆,每个域一个 router 组)
│   ├── enter.go                    #   【入口】聚合所有 RouterGroup
│   ├── system/
│   │   ├── enter.go
│   │   ├── sys_user.go             #   在这注册 /sys/user/* 路由
│   │   └── sys_menu.go
│   └── example/
│       └── enter.go

├── model/                          # 数据模型
│   ├── common/                     #   公共:统一请求/响应、分页
│   │   ├── request/common.go
│   │   └── response/response.go
│   ├── system/                     #   系统域模型(含 request/response 子目录)
│   │   ├── sys_user.go             #     数据库表结构
│   │   ├── request/sys_user.go     #     入参(带 binding 标签)
│   │   └── response/sys_user.go    #     出参(带 json 标签)
│   └── example/
│       └── exa_customer.go

├── middleware/                     # 中间件(jwt、cors、operation 等)
├── initialize/                     # 【装配层】所有初始化代码集中在这
│   ├── router.go                   #   注册路由(把 router/* 接进 Gin Engine)
│   ├── gorm.go                     #   初始化数据库
│   ├── redis.go                    #   初始化 Redis
│   ├── viper.go                    #   读配置
│   └── plugin.go                   #   挂载插件

├── core/                           # 服务核心:启动 Gin Engine、Server
│   ├── server.go
│   └── viper.go

├── global/                         # 全局变量(DB、Redis 实例等,启动后只读)
│   └── global.go

├── config/                         # 配置结构体 + 配置文件
│   ├── config.go
│   └── config.yaml

├── plugin/                         # 插件目录(每个插件自包含一套分层)
│   └── email/                      #   例:邮件插件有自己的 api/router/service/model
│       ├── plugin.go               #     插件入口(被 initialize/plugin.go 加载)
│       ├── api/
│       ├── router/
│       └── service/

├── source/                         # 初始化种子数据(建库后插入初始菜单/角色)
├── utils/                          # 工具函数
├── go.mod
└── go.sum

enter.go 是怎么工作的

api/v1/system/enter.go 为例:

package system

type ApiGroup struct {
    SysUserApi
    SysMenuApi
}

上一层 api/v1/enter.go 再把各域聚合成总入口:

package v1

type ApiGroup struct {
    system.ApiGroup
    example.ApiGroup
}

上层 service / router 同理。这样 handler/service 注册时只认 ApiGroup.ServiceGroup新增一个业务域只动两个 enter.go,不用碰 main.go

三条核心约定

  1. 每个层目录必有 enter.go——作为该层对外的唯一入口。
  2. 按业务域分子目录(system/example/...)——同一域的 handler/service/model 放一起,跨域不混。
  3. 初始化集中在 initialize/——main.go 只调一句 initialize.InitApp(),装配逻辑全收敛在这里。

调用链路:请求 → router/system → ApiGroup(system.SysUserApi) → ServiceGroup(system.SysUserService) → model → DB

怎么选

项目特征推荐
个人项目、Demo、10 接口以内模板1
团队项目、要上线、有 CI/CD模板2
业务边界清晰、模块多、想改动隔离模板3
业务域多、要插件化、长期迭代模板4