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 接口
sUserUser
sOrderOrder
// 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(如 GetListReqCreateRes),然后自动生成 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/entitydo/entity 可整体覆盖,dao 外层可扩展
gen serviceinternal/logicinternal/service 接口与注册文件自动维护
gen ctrlapi/模块/版本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 形成“写完定义,自动补齐骨架”的开发流。

笔记加载中…