Files
easygoadmin-wiki/EasyGoAdmin_GoFrame_EleVue/zh/guide/route.md
T
2026-10-20 21:19:44 +08:00

116 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3.7 服务注册与路由
:::tip 概述
本项目没有传统的路由表文件逐条登记——路由由 Bind 反射绑定从 gmeta 注解自动生成。手工需要维护的只有两处:service 接口文件(手维护)和 router.go 的一行 Bind 注册(生成器自动写入)。
:::
## service 接口文件(手维护,真实代码摘自 internal/service/example.go)
```go
// ============================== 案例演示服务接口 ==============================
// IExample 案例演示服务接口
// 实现位于 internal/logic/example.go
type IExample interface {
// Page 案例演示分页
// 按查询条件分页返回案例演示列表
Page(ctx context.Context, req *v1.ExamplePageReq) (res *v1.ExamplePageRes, err error)
// List 案例演示平铺列表
// data 直接为数组,树形结构由前端构建
List(ctx context.Context, req *v1.ExampleListReq) (res v1.ExampleListRes, err error)
// Detail 案例演示详情
// 按主键ID查询详情
Detail(ctx context.Context, req *v1.ExampleDetailReq) (res *v1.ExampleDetailRes, err error)
// Add 新增案例演示
// 新增成功后返回新记录ID
Add(ctx context.Context, req *v1.ExampleAddReq) (res *v1.ExampleIdRes, err error)
// Update 修改案例演示
// 按主键ID更新记录
Update(ctx context.Context, req *v1.ExampleUpdateReq) (res *v1.ExampleUpdateRes, err error)
// Status 案例演示状态
// 设置记录的状态字段
Status(ctx context.Context, req *v1.ExampleStatusReq) (res *v1.ExampleStatusRes, err error)
// Delete 删除案例演示
// 按主键ID删除单条记录
Delete(ctx context.Context, req *v1.ExampleDeleteReq) (res *v1.ExampleDeleteRes, err error)
// BatchDelete 批量删除案例演示
// 按主键ID列表批量删除记录
BatchDelete(ctx context.Context, req *v1.ExampleBatchDeleteReq) (res *v1.ExampleBatchDeleteRes, err error)
// Import 导入案例演示
// 接收上传的 xls/xlsx 文件并批量导入数据
Import(ctx context.Context, req *v1.ExampleImportReq) (res *v1.ExampleImportRes, err error)
// Export 导出案例演示
// 按查询条件导出数据并返回文件访问地址
Export(ctx context.Context, req *v1.ExampleExportReq) (res *v1.ExampleExportRes, err error)
}
// localExample 案例演示服务实现实例
var localExample IExample
// Example 获取案例演示服务实例
func Example() IExample {
if localExample == nil {
panic("implement not found for interface IExample, forgot register?")
}
return localExample
}
// RegisterExample 注册案例演示服务实现
func RegisterExample(i IExample) {
localExample = i
}
```
三件套缺一不可:**接口 IXxx**(controller 依赖)+ **取用函数 Xxx()**(controller 调用入口)+ **RegisterXxx()**(logic init 注册)。未注册时取用会 panic(启动即暴露配置错误,而非运行时空指针)。
::: warning 禁止 gf gen service
service 接口文件是手工重组维护的(每模块一文件、中文注释齐全)。**禁止整体运行 `gf gen service`**——会按域重新生成并覆盖手工结构。logic 方法签名变更时手工同步接口文件。
:::
## 路由注册(internal/router/router.go)
```go
// 按域顺序注册(摘自 registerControllers)
Bind(s, new(controller.CAuth)) // 认证
Bind(s, new(controller.CIndex)) // 个人中心
Bind(s, new(controller.CUser)) // system 域
Bind(s, new(controller.CRole))
// …
Bind(s, new(controller.CExample)) // 代码生成器注册
```
新增模块时在最后一个 `Bind` 行后追加一行(代码生成器 `registerRouter` 副作用自动写入,已存在则跳过,幂等)。
## 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 扩展标签:
method / path / summary / permission / log / logType / public
3. 按 method:path 注册路由 + 写入路由元数据表 meta.Register
4. 补注册进 gf goai(闭包路由 gf 不会自动收集)→ /api.json 原生 OpenAPI
5. 生成统一包装 handler:
元数据入 ctx → 权限校验(403 短路)→ r.Parse 参数解析(含 gvalid)
→ 调用业务方法 → response.Ok/Fail 信封写出
```
::: tip 注解即事实
权限校验与操作日志共用同一份路由元数据(meta 表),gmeta 标签是唯一真相。不存在"代码改了忘改路由表/权限表"的可能。
:::
## URL 约定
+ 全部路由统一 `/api` 前缀,**URL 中无 `/v1` 版本段**(`api/v1` 只是 Go 包名)。例:`GET /api/user/page`。
+ 公开白名单(`middleware/public.go`,精确匹配):`/api/login`、`/api/register`(白名单放行,路由未注册)、`/api/captcha`、`/api/oauth2/token`、`/api/health`;另放行 `/api.json` 与 `/swagger*`。
+ **三处必须一致**:public.go 白名单 / gmeta `public:"true"` 标注 / router.go 手工注册。
## 注册验证
```sh
go build ./... && ./bin/admin-server.exe
# 启动后检查:
curl http://127.0.0.1:8000/api.json | grep "/api/example" # OpenAPI 已含新路由
# 或配置 server.dumpRouterMap: true 启动看路由表
```