3.6 控制器开发
概述
控制器是 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,平铺放置 | 无子目录 |
控制器里禁止做的事
薄层纪律
- 禁止写业务逻辑——if/for/计算全部下沉 logic。
- 禁止直接 import dao——数据访问只在 logic。
- 禁止手写响应信封——Bind 包装层统一
response.Ok/Fail包装。 - 禁止手写参数解析/权限判断——
r.Parse与HasPerm在包装层完成。 - 需要组合多个 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 注解上。