# 3.10 完整代码清单 :::tip 概述 本节汇总 example 模块的后端四件完整代码(api / controller / service / logic),全部摘自项目实际文件(含注释),可作为手动开发新模块的对照模板。dao 四件为工具产出(见 [3.3 DAO 数据层](./model)),此处不再罗列。 ::: ## 文件对照表 | 文件 | 行数规模 | 职责 | |------|---------|------| | `api/v1/example.go` | ~200 行 | 全部 Req/Res + gmeta 注解 | | `internal/controller/example.go` | ~90 行 | 薄层透传 | | `internal/service/example.go` | ~75 行 | 手维护接口三件套 | | `internal/logic/example.go` | ~200 行 | ModuleSpec 声明 + 委托 + 扩展方法 | ## 一、api/v1/example.go(节选:分页 + 详情 + 新增 + 修改) ```go package v1 import ( "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gmeta" ) // ============================== 案例演示模块(goframe_example) ============================== // ExampleItem 案例演示行数据 // 用于分页列表等场景的基础信息 type ExampleItem struct { Id int `json:"id"` // 主键ID Name string `json:"name"` // 案例名称 Avatar string `json:"avatar"` // 案例图片 Type int `json:"type"` // 案例类型 Status int `json:"status"` // 案例状态 Sort int `json:"sort"` // 案例排序 CreateUser string `json:"createUser"` // 创建人 CreateTime *gtime.Time `json:"createTime"` // 创建时间 StatusText string `json:"statusText"` // 状态显示名(dict_item 解析) } // ExamplePageReq 案例演示分页请求 type ExamplePageReq struct { gmeta.Meta `method:"get" path:"/api/example/page" summary:"案例演示分页" permission:"sys:example:page" log:"案例演示-查询分页记录" logType:"query"` PageReq Name string `json:"name" dc:"案例名称"` // 案例名称 Type int `json:"type" dc:"案例类型"` // 案例类型 Status int `json:"status" dc:"案例状态"` // 案例状态 Keyword string `json:"keyword" dc:"关键词"` // 关键词 } // ExamplePageRes 案例演示分页结果 // 统一壳:records/total/size/current/pages type ExamplePageRes = PageData[ExampleItem] // ExampleDetailReq 案例演示详情请求 type ExampleDetailReq struct { gmeta.Meta `method:"get" path:"/api/example/detail/:id" summary:"案例演示详情" permission:"sys:example:detail" log:"案例演示-查询详情" logType:"query"` Id int64 `json:"id" v:"required#缺少ID" dc:"记录ID"` // 记录ID } // ExampleDetailRes 案例演示详情结果 type ExampleDetailRes struct { Id int64 `json:"id"` // 主键ID Name string `json:"name"` // 案例名称 Avatar string `json:"avatar"` // 案例图片 Type int `json:"type"` // 案例类型 Status int `json:"status"` // 案例状态 Sort int `json:"sort"` // 案例排序 StatusText string `json:"statusText"` // 状态显示名(dict_item 解析) } // ExampleAddReq 新增案例演示请求 type ExampleAddReq struct { gmeta.Meta `method:"post" path:"/api/example/add" summary:"新增案例演示" permission:"sys:example:add" log:"案例演示-新增记录" logType:"add"` Name string `json:"name" v:"required#请输入案例名称" dc:"案例名称"` // 案例名称 Avatar string `json:"avatar" dc:"案例图片"` // 案例图片 Type int `json:"type" dc:"案例类型"` // 案例类型 Status int `json:"status" dc:"案例状态"` // 案例状态 Sort int `json:"sort" dc:"案例排序"` // 案例排序 } // ExampleIdRes 新增返回ID结构 type ExampleIdRes struct { Id int64 `json:"id"` // 主键ID } // ExampleUpdateReq 修改案例演示请求 type ExampleUpdateReq struct { gmeta.Meta `method:"put" path:"/api/example/update" summary:"修改案例演示" permission:"sys:example:update" log:"案例演示-修改记录" logType:"update"` Id int64 `json:"id" v:"required#缺少ID" dc:"记录ID"` // 记录ID Name string `json:"name" v:"required#请输入案例名称" dc:"案例名称"` // 案例名称 Avatar string `json:"avatar" dc:"案例图片"` // 案例图片 Type int `json:"type" dc:"案例类型"` // 案例类型 Status int `json:"status" dc:"案例状态"` // 案例状态 Sort int `json:"sort" dc:"案例排序"` // 案例排序 } // ExampleUpdateRes 修改案例演示结果 type ExampleUpdateRes struct{} ``` 导入导出请求(multipart 与筛选复用): ```go // ExampleImportReq 导入案例演示请求 type ExampleImportReq struct { gmeta.Meta `method:"post" path:"/api/example/import" summary:"导入案例演示" permission:"sys:example:import" log:"案例演示-导入数据" logType:"import"` File *ghttp.UploadFile `p:"file" dc:"导入文件"` } // ExampleExportReq 导出案例演示请求 // 筛选条件与分页一致,导出=所见 type ExampleExportReq struct { gmeta.Meta `method:"get" path:"/api/example/export" summary:"导出案例演示" permission:"sys:example:export" log:"案例演示-导出数据" logType:"export"` Name string `json:"name" dc:"案例名称"` // 案例名称 Type int `json:"type" dc:"案例类型"` // 案例类型 Status int `json:"status" dc:"案例状态"` // 案例状态 } ``` ## 二、internal/controller/example.go(全文结构) 见 [3.6 控制器开发](./controller)——全部方法为一行透传 `return service.Example().Xxx(ctx, req)`。 ## 三、internal/service/example.go(接口三件套) 见 [3.7 服务注册与路由](./route)——`IExample` 接口 + `localExample` 实例 + `Example()` 取用 + `RegisterExample()` 注册。 ## 四、internal/logic/example.go(核心声明与扩展方法) 见 [3.5 逻辑层开发](./logic)。补充导入导出扩展方法(真实代码): ```go // Import 导入案例演示 // 表头为表单字段名,按列序写入 func (s *sExample) Import(ctx context.Context, req *v1.ExampleImportReq) (res *v1.ExampleImportRes, err error) { _, rows, err := excel.ReadSheet(req.File) if err != nil { return nil, err } res = &v1.ExampleImportRes{Total: len(rows)} for i, row := range rows { if cellAt(row, 0) == "" { res.Failed++ res.Reasons = append(res.Reasons, fmt.Sprintf("第%d行:案例名称为空", i+2)) continue } if _, e := dao.Example.Ctx(ctx).Data(map[string]any{ "name": cellAt(row, 0), "avatar": cellAt(row, 1), "type": cellInt(row, 2, 0), "status": cellInt(row, 3, 0), "sort": cellInt(row, 4, 0), }).Insert(); e != nil { res.Failed++ res.Reasons = append(res.Reasons, fmt.Sprintf("第%d行:写入失败 %v", i+2, e)) continue } res.Success++ } return res, nil } // Export 导出案例演示 // 与列表同套筛选条件,枚举列输出字典文本 func (s *sExample) Export(ctx context.Context, req *v1.ExampleExportReq) (res *v1.ExampleExportRes, err error) { rows, err := exampleSpec.applyFilters(ctx, exampleSpec.Model(ctx), req).Order("sort, id").All() if err != nil { return nil, err } headers := []string{"案例名称", "案例图片", "案例类型", "案例状态", "案例排序"} data := make([][]any, 0, len(rows)) for _, r := range rows { data = append(data, []any{r["name"].String(), r["avatar"].String(), DictGetText(ctx, "example_type", r["type"]), DictGetText(ctx, "example_status", r["status"]), r["sort"].String()}) } fileName, _, err := excel.WriteSheet(upload.BaseDir(ctx), "案例演示数据", headers, data) if err != nil { return nil, err } url := upload.GetFileUrl(ctx, fileName) return &url, nil } ``` ## 使用方式 手动开发新模块时,以本清单为骨架逐文件替换模块名与字段;或直接用生成器产出同等结构后再微调(生成器模板即按此规范制作): ```sh go run ./cmd/generator -tables "goframe_example|案例演示表" go build ./... # 编译并重启 ```