From 0096775d318d6fe6fb9a3597c6ec8dfd55b7ddd7 Mon Sep 17 00:00:00 2001 From: Rogee Date: Thu, 11 Sep 2025 22:54:19 +0800 Subject: [PATCH] update gen routes --- templates/project/README.md.raw | 103 +++++++++++++++++++------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/templates/project/README.md.raw b/templates/project/README.md.raw index 2f0b683..7e1274b 100644 --- a/templates/project/README.md.raw +++ b/templates/project/README.md.raw @@ -1,68 +1,87 @@ -## 路由定义 +## 路由生成(gen route) -路由由控制器方法的注释进行声明式定义,解析器会从 Go AST 中读取注释、方法签名与参数列表,生成对应的路由注册与参数绑定代码。 +通过在控制器方法上编写注释,解析器从 Go AST 中读取注释、方法签名与参数列表,自动生成路由注册与参数绑定代码。 -- 关键标签:`@Router` 定义路径与方法;`@Bind` 定义方法参数与其来源位置及键名。 -- 生成行为:根据注释规则生成 `router.(path, FuncN(...))` 或 `DataFuncN(...)` 包装调用,并自动汇聚所需 imports 与控制器注入字段。 +- 核心标签:`@Router` 定义路径与方法;`@Bind` 定义方法参数的来源与键名。 +- 生成行为:输出 `router.(path, FuncN(...))` 或 `DataFuncN(...)` 包装调用,并自动汇聚所需 imports 与控制器注入字段。 + +### 快速开始 + +``` +atomctl gen route [path] +``` + +- 生成文件:当前包目录下 `routes.gen.go` +- 分组与排序:按控制器分组,导入、方法、路由项稳定排序,便于审阅 diff。 ### 注释语法 - `@Router []` - - 例如:`@Router /users/:id [get]` + - 示例:`@Router /users/:id [get]` - - `@Bind [key()] [model(|[:])]` - - `paramName` 必须与方法参数名一致(大小写敏感) - - `position` 取值:`path`、`query`、`body`、`header`、`cookie`、`local`、`file` +- `@Bind [key()] [model(|[:])]` + - `paramName` 与方法参数名一致(大小写敏感) + - `position`:`path`、`query`、`body`、`header`、`cookie`、`local`、`file` - 可选: - `key()` 覆盖默认键名; - - `model()` 支持两种写法: - - 仅字段:`model(id)`(推荐;模型类型由参数类型推断) - - 类型+字段:`model(database/models.User:id)` 或 `model(database/models.User)`(字段缺省为 `id`) + - `model()` 详见“模型绑定”。 -### 参数来源与绑定生成 +### 参数绑定规则(按 position) -根据 `position` 与参数类型(是否标量)生成绑定器调用: - -- query - - 标量类型:`QueryParam[T]("key")` - - 非标量类型:`Query[T]("key")` -- path - - 标量类型:`PathParam[T]("key")` - - 非标量类型:`Path[T]("key")` - - 若声明了 `model()` 且 position 为 `path`:生成 `PathModel[T]("field", "key")`,表示根据路径参数值按 `field` 查询并绑定为 `T` 实例(`T` 来自方法参数类型)。 +- query:标量用 `QueryParam[T]("key")`,非标量用 `Query[T]("key")` +- path:标量用 `PathParam[T]("key")`,非标量用 `Path[T]("key")` + - 若使用 `model()`(仅在 path 有效),会按字段值查询并绑定为 `T`,详见下文 - header:`Header[T]("key")` - body:`Body[T]("key")` -- cookie - - `string`:`CookieParam("key")` - - 其他:`Cookie[T]("key")` +- cookie:`string` 用 `CookieParam("key")`,其他用 `Cookie[T]("key")` - file:`File[multipart.FileHeader]("key")` - local:`Local[T]("key")` 说明: -- 标量类型集合(影响是否使用 `Param` 后缀):`string`、`int`、`int32`、`int64`、`float32`、`float64`、`bool`。 -- `key` 默认与 `paramName` 相同;若设置 `key(...)` 则使用其值。 -- `file` 使用固定类型参数 `multipart.FileHeader`(请确保依赖可用)。 +- 标量类型集合:`string`、`int`、`int32`、`int64`、`float32`、`float64`、`bool` +- `key` 默认等于 `paramName`;设置 `key(...)` 后以其为准 +- `file` 使用固定类型 `multipart.FileHeader` ### 类型与指针处理 -- 支持 `T`、`*T`、`pkg.T`、`*pkg.T` 形式;会正确记录选择子表达式对应的 import。 -- 忽略结尾为 `Context` 或 `Ctx` 的参数(视为框架上下文)。 -- 指针处理:除 `local` 外,会去掉前导 `*` 作为泛型实参;`local` 保留指针(便于写回)。 +- 支持 `T`、`*T`、`pkg.T`、`*pkg.T`;会正确收集选择子表达式对应 import +- 忽略结尾为 `Context` 或 `Ctx` 的参数(框架上下文) +- 指针处理:除 `local` 外会去掉前导 `*` 作为泛型实参;`local` 保留指针(便于写回) -### 解析与匹配规则 +### 解析与匹配 -- 先收集注释中的多条 `@Bind`,再按“方法参数列表顺序”匹配并输出绑定器,确保调用顺序与方法签名一致。 -- 未在方法参数中的 `@Bind` 会被忽略;缺失 `@Router` 或方法无注释将跳过该方法。 -- import 自动收集去重;控制器注入字段名为类型名的小驼峰形式,例如:`userController *UserController`。 +- 先收集注释中的多条 `@Bind`,再按“方法参数列表顺序”匹配并输出绑定器,确保调用顺序与方法签名一致 +- 未在方法参数中的 `@Bind` 会被忽略;缺失 `@Router` 或方法无注释将跳过该方法 +- import 自动收集去重;控制器注入字段名为类型名的小驼峰形式,例如 `userController *UserController` -### 返回值与包装函数名 +### 返回值与包装函数 -- 若方法返回值个数 > 1:使用 `DataFuncN`(包含数据与错误等返回)。 -- 否则使用 `FuncN`。 -- 其中 `N` 为参与绑定的参数个数。 +- 返回值个数 > 1:使用 `DataFuncN` +- 否则使用 `FuncN` +- `N` 为参与绑定的参数个数 -### 示例 +### 模型绑定(path + model) + +当 `@Bind ... model(...)` 配合 `position=path` 使用时,将根据路径参数值查询模型并绑定为方法参数类型的实例(`T` 来自方法参数)。 + +- 语法: + - 仅字段:`model(id)`(推荐) + - 指定字段与类型:`model(id:int)`、`model(code:string)`(用于非字符串路径参数) + - 指定类型与字段:`model(pkg.Type:field)` 或 `model(pkg.Type)`(字段缺省为 `id`) +- 行为: + - 生成的绑定器会按给定字段构造查询条件并返回首条记录 + - 自动注入 import:`field "go.ipao.vip/gen/field"`,用于构造字段条件表达式 + +示例: + +```go +// @Router /users/:id [get] +// @Bind user path key(id) model(id) +func (uc *UserController) Show(ctx context.Context, user *models.User) (*UserDTO, error) +``` + +### 完整示例 注释与方法签名: @@ -90,6 +109,6 @@ router.Get("/users/:id", DataFunc4( ### 错误与限制 -- 无效的 `@Router` 语法会报错;无效的 `position` 会在解析阶段触发错误。 -- `file` 目前仅支持单文件头;`model()` 仅在 `position=path` 时参与代码生成(使用 `PathModel`)。 -- 请与实际路由段保持一致(特别是 `path` 的 `key` 与路径变量名)。 +- 无效的 `@Router` 语法会报错;无效的 `position` 会在解析阶段触发错误 +- `file` 仅支持单文件头;`model()` 仅在 `position=path` 时参与代码生成 +- 请确保路由段变量名与 `key(...)` 保持一致