gf gen service 与 gen ctrl:代码生成进阶
上一章用 gf gen dao 解决了“表 → 数据层代码”。业务逻辑增多后,接口层与业务层还有两类重复劳动:logic 实现与 service 接口的重复声明、api 定义与 controller 实现的机械对应。官方为此提供了 gf gen service(v2.1+)与 gf gen ctrl(v2.5+,仅 HTTP),本章说明思路与生成物结构。
gf gen service:由实现生成接口
官方工程规范中 internal/logic 放业务实现、internal/service 放业务接口,模块间通过接口解耦。手动维护两份“同名方法”很容易漏改,gen service 的做法是从实现反推接口:
$ gf gen service -h
USAGE
gf gen service [OPTION]
OPTION
-s, --srcFolder 解析源码目录,默认 internal/logic
-d, --dstFolder 生成接口目录,默认 internal/service
-a, --stPattern 匹配业务结构体的正则,默认 ^s([A-Z]\w+)$
它只解析 logic 下的二级目录代码(logic/xxx/*.go),按正则识别模块结构体并生成对应接口文件:
| logic 结构体 | 生成的 service 接口 |
|---|---|
sUser | User |
sOrder | Order |
// internal/logic/user/user.go(开发者手写)
type sUser struct{}
func (s *sUser) GetList(ctx context.Context, in model.UserGetListInput) (out model.UserGetListOutput, err error) {
// 业务实现...
return
}
// 执行 gf gen service 后自动生成 internal/service/user.go 接口,
// 并在 internal/logic 里补上 service.RegisterUser(new(sUser)) 这类注册调用
每次改完 logic 重新执行 gf gen service 即可。它同时会生成一个“接口实现注册文件”,需在 main 包最顶部(packed 之后)以空行隔开的方式引入,程序启动时完成实现注入。官方同时指出:该特性是实验性的、可选方案,标准做法仍是“先定义 service 接口、再写 logic 实现”,两种方式官方都支持。
gf gen ctrl:由 api 定义生成控制器
gen ctrl 解决的是“接口定义与控制器实现重复”:约束 api 按 /api/模块/版本/定义文件.go 组织,结构体命名为 操作+Req/Res(如 GetListReq、CreateRes),然后自动生成 internal/controller 下的接口与实现骨架:
api/user/v1/user.go: type UserCreateReq/UserCreateRes、UserGetListReq/Res ...
执行 gf gen ctrl 后:
internal/controller/user/v1/user.go # 接口绑定(路由注册入口)
internal/controller/user/v1/user_create.go # 每个 API 一个实现文件
// internal/controller/user/v1/user_create.go(生成后由开发者填充)
package v1
import (
"context"
"goframe-demo/api/user/v1"
)
func (c *Controller) Create(ctx context.Context, req *v1.UserCreateReq) (res *v1.UserCreateRes, err error) {
// 校验输入参数、组装返回数据
return
}
它还能按 -k/--sdkPath 同时生成 HTTP SDK 代码(默认关闭),-c/--clear 删除与 api 定义不匹配的历史控制器文件。IDE 配合官方 watchers 配置可实现保存即增量生成。
生成物结构对比
| 命令 | 输入 | 输出 | 覆盖/保留策略 |
|---|---|---|---|
gen dao | 数据库表 | dao/do/entity | do/entity 可整体覆盖,dao 外层可扩展 |
gen service | internal/logic | internal/service 接口与注册文件 | 自动维护 |
gen ctrl | api/模块/版本 | internal/controller 骨架 | 每个 API 一个文件,减少协作冲突 |
注意事项
gen service无法处理继承/嵌套场景的方法,此类模块建议手动维护接口(手动文件不会被工具覆盖)。gen ctrl默认每个 API 生成一个 controller 文件,避免多人改同一大文件冲突;-m/--merge可合并为按源文件生成。- controller 的职责是“校验入参、编排逻辑、组装返回”,不要把业务实现都塞进 controller,否则 service 层失去复用价值。
- 两个命令的细节与模板均为官方 CLI 提供,行为差异以官方文档 goframe.org 为准。
小结
gen service 让接口与实现少写一半样板,gen ctrl 让 api 定义与控制器一一对应并顺带产出 SDK。建议:小项目先只用 gen dao;业务模块多了再上 gen service/ctrl,并配合 IDE watchers 形成“写完定义,自动补齐骨架”的开发流。