项目目录结构:官方单仓布局 api/internal/hack/manifest 讲解
引言
gf init 生成的项目骨架不是随便排的目录,而是官方推荐的"单仓(monorepo 风格)工程布局"。理解每个目录的职责,才知道代码该放哪里。本章按官方文档 goframe.org 的工程目录设计章节讲解。
概念
工程按"对外接口"与"内部实现"分层,典型目录树如下:
project/
├── api/ # 对外接口定义:请求/响应结构体(Req/Res),可被外部复用
├── hack/ # 开发辅助:代码生成配置与脚本(如 gf gen 相关配置)
├── internal/ # 内部实现,不允许被外部直接引用
│ ├── cmd/ # 命令行入口,main.go 调用 cmd 包启动服务
│ ├── controller/ # 控制器:接收请求,负责参数与响应编排
│ ├── dao/ # 数据访问对象,由 gf gen dao 生成
│ ├── logic/ # 业务逻辑实现
│ ├── model/ # 内部数据结构(entity/do 等,常由代码生成)
│ └── service/ # 服务接口定义,logic 实现、controller 调用
├── manifest/ # 工程配置与部署文件
│ ├── config/ # 配置文件,如 config.yaml
│ ├── docker/ # 镜像构建相关
│ ├── deploy/ # 部署编排相关
│ ├── protobuf/ # proto 定义(用到时才有)
│ └── sql/ # 数据库初始化脚本
├── resource/ # 静态资源:public/、template/ 等
├── utility/ # 通用工具函数
├── main.go # 程序入口
├── Makefile
└── go.mod
调用方向一般是:main → cmd 启动服务 → 请求进入 controller → controller 调 service 接口 → logic 实现业务 → dao 访问数据库。这样依赖单向、职责清晰。
代码示例
main.go 只做一件事——把控制权交给 internal/cmd:
package main
import (
"github.com/gogf/gf/v2/os/gctx"
"project/internal/cmd"
)
func main() {
cmd.Main.Run(gctx.GetInitCtx())
}
internal/cmd 中定义启动命令(脚手架默认还会注册统一返回等中间件):
package cmd
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Main = gcmd.Command{
Name: "main",
Usage: "main",
Brief: "启动 HTTP 服务",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
s := g.Server()
s.Run()
return nil
},
}
)
注意点
internal目录是 Go 语言层面的访问限制:只有同模块内的代码可以引用它。api目录的结构体往往带g.Meta标签(规范路由用),与internal/controller一一对应。dao/model推荐由gf gen dao生成,不要手工维护。- 目录随版本有细微演进,例如新版本可能新增
internal/consts等,以实际生成为准。
小结
本章的目录即"官方单仓布局":接口(api)、实现(internal)、配置部署(manifest)、资源(resource)各归其位。后续章节的示例大多发生在 internal/controller 与 api 中。细节以官方文档 goframe.org 的工程目录章节为准。