Skip to content

3.10 完整代码清单 ​

概述

本节汇总 example 模块的后端四件完整代码(api / controller / service / logic),全部摘自项目实际文件(含注释),可作为手动开发新模块的对照模板。dao 四件为工具产出(见 3.3 DAO 数据层),此处不再罗列。

文件对照表 ​

文件行数规模职责
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 控制器开发——全部方法为一行透传 return service.Example().Xxx(ctx, req)。

三、internal/service/example.go(接口三件套) ​

见 3.7 服务注册与路由——IExample 接口 + localExample 实例 + Example() 取用 + RegisterExample() 注册。

四、internal/logic/example.go(核心声明与扩展方法) ​

见 3.5 逻辑层开发。补充导入导出扩展方法(真实代码):

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 ./...   # 编译并重启

小蚂蚁云团队 · 提供技术支持