# 3.6 控制器开发 :::tip 概述 控制器是 HTTP 薄层,只做一件事:把解析好的请求转发给 service 接口。不写业务、不操作数据库、不组装复杂响应——所有逻辑在 logic 层。这个"薄"是有意为之:让权限、日志、参数解析统一收敛到 Bind 包装层。 ::: ## 真实代码(摘自 internal/controller/example.go) ```go package controller import ( "context" "easygoadmin/api/v1" "easygoadmin/internal/service" ) // ============================== 案例演示控制器 ============================== // CExample 案例演示控制器 // 薄层控制器,仅负责参数透传,业务逻辑由 service.Example() 处理 type CExample struct{} // Page 案例演示分页 // 按查询条件分页返回案例演示列表 func (c *CExample) Page(ctx context.Context, req *v1.ExamplePageReq) (res *v1.ExamplePageRes, err error) { return service.Example().Page(ctx, req) } // List 案例演示平铺列表 // data 直接为数组,树形结构由前端 buildTree 构建 func (c *CExample) List(ctx context.Context, req *v1.ExampleListReq) (res v1.ExampleListRes, err error) { return service.Example().List(ctx, req) } // Detail 案例演示详情 // 按主键ID查询详情 func (c *CExample) Detail(ctx context.Context, req *v1.ExampleDetailReq) (res *v1.ExampleDetailRes, err error) { return service.Example().Detail(ctx, req) } // Add 新增案例演示 // 新增成功后返回新记录ID func (c *CExample) Add(ctx context.Context, req *v1.ExampleAddReq) (res *v1.ExampleIdRes, err error) { return service.Example().Add(ctx, req) } // Update 修改案例演示 // 按主键ID更新记录 func (c *CExample) Update(ctx context.Context, req *v1.ExampleUpdateReq) (res *v1.ExampleUpdateRes, err error) { return service.Example().Update(ctx, req) } // Status 案例演示状态 // 设置记录的状态字段 func (c *CExample) Status(ctx context.Context, req *v1.ExampleStatusReq) (res *v1.ExampleStatusRes, err error) { return service.Example().Status(ctx, req) } ``` ## 方法签名约定 ```go func (c *CXxx) 方法名(ctx context.Context, req *v1.XxxReq) (res *v1.XxxRes, err error) ``` 这是 Bind 反射绑定的硬约束:**入参必须是指针请求结构体,出参必须是(结果指针, error)**。签名不匹配的方法不会被注册路由(静默跳过),排障时注意。 ## 命名规则 | 项 | 规则 | 示例 | |----|------|------| | 控制器类型 | `C` + 模块 Pascal | `CExample`、`CConfigItem` | | 文件名 | 表名去前缀 snake_case | `example.go`、`config_item.go` | | 方法名 | 与 logic/接口方法名一致 | `Page`/`Add`/`BatchDelete` | | 包 | 单包 `controller`,平铺放置 | 无子目录 | ## 控制器里禁止做的事 ::: warning 薄层纪律 1. **禁止写业务逻辑**——if/for/计算全部下沉 logic。 2. **禁止直接 import dao**——数据访问只在 logic。 3. **禁止手写响应信封**——Bind 包装层统一 `response.Ok/Fail` 包装。 4. **禁止手写参数解析/权限判断**——`r.Parse` 与 `HasPerm` 在包装层完成。 5. 需要组合多个 service 调用时,逻辑放 logic 层的一个聚合方法,controller 仍只透传。 ::: ## 特殊控制器参考 | 控制器 | 特点 | |--------|------| | `CAuth` | 登录/登出/验证码/令牌,gmeta 带 `public:"true"` | | `CIndex` | 个人中心聚合(getUser/getMenus/updatePassword/updateProfile) | | `COnlineUser` | 无表模块,数据源 Redis | | `CUpload` | multipart 上传(`*ghttp.UploadFile` + `p:"file"` 标签) | | `CGenerator` | 工具类,Preview/Generate/BatchGenerate | 控制器不区分"标准/特殊"写法——统一薄层透传,差异全部体现在请求结构体的 gmeta 注解上。