# 3.6 接口层开发(handler) :::tip 概述 handler 是极薄委托层:`router.Bind` 反射已完成参数解析与 binding 校验,本层只做一次调用转换。**业务规则一律在 service,handler 不写逻辑。** ::: ## 标准结构 ```go // internal/handler/example.go package handler import ( "context" "easygoadmin/internal/model/dto" "easygoadmin/internal/service" ) // CExample 案例演示控制器 type CExample struct{} // Page 案例演示分页(GET /api/example/page),委托 service.Example.Page func (c *CExample) Page(ctx context.Context, req *dto.ExamplePageReq) (*dto.PageData[dto.ExampleItem], error) { return service.Example.Page(ctx, req) } // Add 新增案例演示(POST /api/example/add),委托 service.Example.Add func (c *CExample) Add(ctx context.Context, req *dto.ExampleAddReq) (*dto.ExampleIdRes, error) { return service.Example.Add(ctx, req) } ``` ## 方法签名铁律 每个对外方法签名**必须**是: ```go func (c *CXxx) Method(ctx context.Context, req *dto.XxxReq) (*dto.XxxRes, error) ``` 路由反射扫描靠这个签名识别方法并绑定请求——签名不匹配的方法不会被注册(也不会报错,表现为 404)。返回值可以是结构体指针、类型别名(如 `dto.ExampleListRes`)或 `*dto.EmptyRes`。 ## 手写逻辑方法的注释规约 非标准方法(导入/导出/重置密码/分配菜单等)保留为 handler 方法,按"入参/返回/副作用"三段注释: ```go // internal/handler/example.go // Import 导入案例演示(POST /api/example/import),委托 service.Example.Import // 入参:multipart 表单 xls/xlsx 文件(dto 实现 UnmarshalBody 解析文件字段)。 // 返回:导入总数、成功数、失败数及失败原因列表;错误:文件缺失或格式非法时上抛。 // 副作用:解析表格并批量写入案例演示表。 func (c *CExample) Import(ctx context.Context, req *dto.ExampleImportReq) (*dto.ExampleImportRes, error) { return service.Example.Import(ctx, req) } ``` ## handler 不做的事 | 禁则 | 去处 | |---|---| | 参数解析与校验 | router.Bind(binding 标签驱动)+ dto | | 权限判断 | authz 中间件(RouteSpec.Permission 声明) | | 操作日志 | operation_log 中间件(RouteSpec.Log 声明) | | 业务规则与事务 | service | | 数据访问 | repository(经 service 调用) | ## 新控制器接入 在 `internal/router/router.go` 的 `registerControllers` 中加一条 `Bind` 声明(含 RouteSpec 表)——见下一页 [3.7 路由与元数据注册](/zh/guide/route.html)。代码生成器会自动完成这一步。 ## 编写检查清单 - [ ] 控制器名 `CXxx`,空结构体 - [ ] 方法与 dto 请求结构一一对应,签名完全匹配 - [ ] 方法体只有一行委托(或极少量调用转换) - [ ] 注释给出路由方法与路径 ## 下一步 → [3.7 路由与元数据注册(RouteSpec)](/zh/guide/route.html)