# 3.7 路由与元数据注册(RouteSpec) :::tip 概述 本项目的路由**只有一处声明**:`router.go` 内每个控制器的 RouteSpec 表。注册、权限校验、操作日志、公开白名单、OpenAPI 文档全部从这一份声明派生,天然同步。 ::: ## RouteSpec 字段 ```go // internal/router/bind.go type RouteSpec struct { Method string // HTTP 方法:GET/POST/PUT/DELETE(必填,否则不注册) Path string // 路由模板,如 /api/link/detail/:id(必填) Summary string // 接口摘要(OpenAPI) Permission string // 权限节点 sys:link:page;空表示登录即可 Log string // 操作日志标题;空表示不记录 LogType string // 日志类型:query/add/update/delete/import/export/reset… Public bool // 免登录(登录、验证码等) } ``` ## 注册写法 在 `internal/router/router.go` 的 `registerControllers` 内,为控制器集中声明(方法名 → 路由元数据,按字典序排列): ```go // internal/router/router.go Bind(rg, new(handler.CExample), map[string]RouteSpec{ "Add": {Method: "POST", Path: "/api/example/add", Summary: "新增案例演示", Permission: "sys:example:add", Log: "案例演示-新增记录", LogType: "add"}, "BatchDelete": {Method: "DELETE", Path: "/api/example/batchDelete", Summary: "批量删除案例演示", Permission: "sys:example:batchDelete", Log: "案例演示-批量删除记录", LogType: "delete"}, "Delete": {Method: "DELETE", Path: "/api/example/delete/:id", Summary: "删除案例演示", Permission: "sys:example:delete", Log: "案例演示-删除记录", LogType: "delete"}, "Detail": {Method: "GET", Path: "/api/example/detail/:id", Summary: "案例演示详情", Permission: "sys:example:detail", Log: "案例演示-查询详情", LogType: "query"}, "Export": {Method: "GET", Path: "/api/example/export", Summary: "导出案例演示", Permission: "sys:example:export", Log: "案例演示-导出数据", LogType: "export"}, "Import": {Method: "POST", Path: "/api/example/import", Summary: "导入案例演示", Permission: "sys:example:import", Log: "案例演示-导入数据", LogType: "import"}, "List": {Method: "GET", Path: "/api/example/list", Summary: "案例演示列表", Permission: "sys:example:list", Log: "案例演示-查询列表", LogType: "query"}, "Page": {Method: "GET", Path: "/api/example/page", Summary: "案例演示分页", Permission: "sys:example:page", Log: "案例演示-查询分页记录", LogType: "query"}, "Status": {Method: "PUT", Path: "/api/example/status", Summary: "案例演示状态", Permission: "sys:example:status", Log: "案例演示-设置状态", LogType: "update"}, "Update": {Method: "PUT", Path: "/api/example/update", Summary: "修改案例演示", Permission: "sys:example:update", Log: "案例演示-修改记录", LogType: "update"}, }) ``` ## 注册后发生什么 `router.Bind` 反射扫描控制器: ```text 按签名筛选方法(ctx, *dto.Req)→(*dto.Res, error) │ ▼ 按方法名查 RouteSpec 表 → rg.Handle(Method, Path, 包装函数) │ ▼ 包装函数内:绑定解析(path > body > query)→ binding 校验 → 调 handler → 信封响应 │ ▼ 写入路由元数据表(方法名、路径、权限码、日志配置、公开标记) │ ▼ authz / operation_log / public / OpenAPI 从元数据表消费同一份声明 ``` ## 声明规约 | 项 | 规约 | |---|---| | 路径 | `/api/{模块}/{动作}`,路径参数用 `:id` | | 方法映射 | 查询 GET / 新增 POST / 修改 PUT / 删除 DELETE | | 权限码 | `sys:{模块}:{动作}`,动作与路径动词一致 | | Permission 为空 | 登录即可访问(不校验权限点) | | Log 为空 | 不记录操作日志;查询类是否记录还受 `operationLog.logQuery` 开关控制 | | Public | 仅登录、验证码、令牌兑换等真正公开接口使用 | | 顺序 | 表内按方法名字典序排列,与既有条目风格逐字一致 | ## 新增接口的完整动作 1. dto 加请求/响应结构 2. service 加方法 3. handler 加同签名方法 4. RouteSpec 表加一条声明 5. 需要权限点时在菜单管理中配置权限节点(见下一页) ## 底层机制深入 反射细节、元数据表结构、中间件如何消费元数据 → [4.4 反射元数据驱动机制](/zh/architecture/bind-mechanism.html)。 ## 下一步 → [3.8 参数校验与错误上抛](/zh/guide/validation.html)