7.4 数据导入导出
概述
Excel 导入导出基于 xuri/excelize/v2(utility/excel 封装):导入解析逐行校验写入并返回统计,导出走 ChunkQuery 分批查询防 OOM。启用模块:user / level / example。
utility/excel API
text
ReadSheet(file FileOpener):首行表头,全单元格转字符串(TrimSpace),空行跳过;
FileOpener 接口兼容 *ghttp.UploadFile 与 *multipart.FileHeader
WriteSheet(dir, baseName, headers, rows [][]any):写文件返回 (fileName, filePath)导入流程(Import,真实模式摘自 example)
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
}要点:逐行独立成败(一行失败不影响后续);返回 Total/Success/Failed/Reasons(逐行原因);user 导入还含唯一校验/租户上限/默认密码 bcrypt 预计算/角色与城市解析(ResolveCityCodes)。
导出流程(Export,真实模式摘自 example)
go
// 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
}要点:导出统一走 xxxSpec.applyFilters 与列表同套筛选(导出=所见);枚举列 DictGetText 转文本;大结果集用 ChunkQuery 分批(user 导出 500/页)。
导入导出规范
| 项 | 规范 |
|---|---|
| 接口 | Import POST multipart(p:"file");Export GET + 筛选参数 |
| 杅限 | sys:{module}:import / export |
| 日志 | logType import / export("模块名-导入数据/导出数据") |
| 模板 | 表头=表单字段名(导出文件即导入模板) |
| 文件位置 | 导出写临时文件返回 URL(/upload/temp/...,受 temp 清理回收) |
| 防 OOM | 大结果集 ChunkQuery 分批(默认 500/页) |
前端组件
text
Excel 组件(components/Excel + importFile):
导入:选文件 → POST /api/{module}/import → 展示统计与失败原因
导出:调 /api/{module}/export → 拿 URL → downloadFile 下载
详见 9.11 Excel 导入导出组件开发新模块的导入导出
text
1. 请求结构:ExampleImportReq(gmeta + File 字段)/ ExampleExportReq(gmeta + 筛选字段)
2. 接口声明:service 接口加 Import/Export 方法
3. logic 实现:按上方真实模式(ReadSheet 逐行 / applyFilters + WriteSheet)
4. 权限节点:import/export(生成器 HasImport/HasExport 默认 true 自动建)
5. 前端:导入按钮 + 导出按钮(模板参照 example 页面)