# 5.18 gmeta 注解系统总览 :::tip 概述 gmeta 注解是本项目的"声明即事实"机制:请求结构体上的一个 gmeta.Meta 标签同时驱动路由注册、权限校验、操作日志、OpenAPI 文档四件事。解析与分发在 internal/router/bind.go(反射绑定)与 meta/(路由元数据表)。 ::: ## 一个标签,四份事实 ```go type UserPageReq struct { gmeta.Meta `method:"get" path:"/api/user/page" summary:"用户分页" permission:"sys:user:page" log:"用户管理-查询分页记录" logType:"query"` // ... } ``` ```text 解析后同时产出: ① 路由注册 GET /api/user/page → CUser.Page ② 权限校验 HasPerm("sys:user:page")(包装层每请求判定) ③ 操作日志 标题"用户管理-查询分页记录"、类型 query ④ OpenAPI 文档 /api.json 的 path/summary/参数说明 ``` 不存在"代码改了忘改路由表/权限表/文档"——标签是唯一真相。 ## 标签字段语义 | 标签 | 语义 | |------|------| | `method` | HTTP 方法(get/post/put/delete) | | `path` | 完整路由模板(含 /api 前缀;`:id` 为路由参数,req 同名字段承接) | | `summary` | OpenAPI 摘要 | | `permission` | 权限节点 `sys:{module小驼峰}:{action}`;空 = 登录即可 | | `log` | 操作日志标题 `"{模块中文名}-{动作}"`;空 = 不记录 | | `logType` | 日志类型字符串(query/add/update/delete/import/export/reset/…),经 LogTypeMap 转 41 个枚举值 | | `public` | `"true"` = 免登录(仍需与 middleware/public.go 白名单一致) | ## Bind 绑定流程(internal/router/bind.go) ```text Bind(s, new(controller.CXxx)) 扫描控制器全部导出方法: 1) 校验签名:func (c *Xxx) Page(ctx, req *v1.XxxReq) (*v1.XxxRes, error) (签名不符静默跳过——排障注意) 2) 解析请求结构体内嵌 gmeta.Meta 扩展标签 3) 按 method:path 注册路由 + meta.Register(rm) 写入路由元数据表 (键 "METHOD /path",读写锁保护;Lookup 供调试,All 供文档生成) 4) 补注册进 gf goai(闭包路由 gf 不会自动收集)→ /api.json 原生 OpenAPI 5) 生成统一包装 handler: 路由元数据写入 ctx(操作日志中间件读取) → 权限校验(403 短路;不设独立 Permission 中间件) → r.Parse(req)(路由参数+query+body,含 gvalid 校验) → 调用业务方法 → response.Ok/Fail 信封写出 ``` ## BodyUnmarshaler 逃生舱 ```text 当请求体顶层形态无法用结构体标签表达(如平铺 map)时, Req 实现 UnmarshalBody(r *ghttp.Request) error 接口: → 跳过默认 Parse,实现内自行完成解析与 gvalid 校验 ``` ## 注册验证 ```sh # OpenAPI 检查(gmeta 补注册后全量可用) curl http://127.0.0.1:8000/api.json | grep "user/page" # 启动路由表 # config.yaml: server.dumpRouterMap: true ``` ## 开发规约 ```text * 每个接口必须有 gmeta——没有标签的方法不会注册路由 * permission 新码必须同步菜单节点 + 角色勾选(否则 403) * public:"true" 必须同时出现在 middleware/public.go 白名单(三处一致) * log 空 = 不记录(有意不记录才留空);logType 缺省按 HTTP 方法自动推断(0) * path 一律 /api 开头、无 /v1 版本段 * 改 path/permission 等标签后重启生效(路由与元数据表启动期构建) ```