Beego 不支持 Excel 导入导出,需用 excelize/v2;不能用 WriteString 输出,须设正确 Content-Type 和 Content-Disposition,并用 f.Bytes() 写二进制数据。

Beego 本身不提供 Excel 导入导出能力,必须靠第三方库配合实现,最常用的是 github.com/tealeg/xlsx 和 github.com/xuri/excelize/v2 —— 后者更现代、支持 .xlsx 全特性、无 CGO 依赖,推荐直接用它。
为什么不能直接用 beego.Controller.Ctx.WriteString 写 Excel?
因为 Excel(尤其是 .xlsx)是 ZIP 封装的 XML 结构,不是纯文本。用 WriteString 只会输出乱码或损坏文件;浏览器也无法识别 MIME 类型,下载后打不开。
- 正确做法是设置
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - 同时设置
Content-Disposition: attachment; filename="data.xlsx"强制下载 - 最后调用
c.Ctx.ResponseWriter.Write()输出二进制数据,而非字符串
用 excelize 实现 Excel 导出(含中文、日期、数字格式)
关键点在于:创建工作簿 → 添加 Sheet → 写入单元格 → 设置样式 → 写入响应体。注意 Beego 的 c.Data["json"] 或 c.ServeJSON() 完全不适用。
- 导入包:
"github.com/xuri/excelize/v2" - 导出时不要用
f.WriteTo(w)直接写响应体(可能 panic),应先f.Bytes()获取字节切片再写 - 中文需确保字体存在(默认 Calibri 支持中文),否则显示为方框;可显式设字体:
f.SetCellStyle("Sheet1", "A1", "A1", styleID) - 日期列建议用
f.SetCellDateTime()而非SetCellValue(),否则 Excel 识别为字符串
func (c *ExportController) Get() {
f := excelize.NewFile()
index := f.NewSheet("Sheet1")
f.SetCellValue("Sheet1", "A1", "用户名")
f.SetCellValue("Sheet1", "B1", "注册时间")
f.SetCellDateTime("Sheet1", "B2", time.Now(), "yyyy-mm-dd hh:mm:ss")
f.SetActiveSheet(index)
c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
c.Ctx.ResponseWriter.Header().Set("Content-Disposition", `attachment; filename="users.xlsx"`)
if err := c.Ctx.ResponseWriter.Write(f.Bytes()); err != nil {
beego.Error("Excel write failed:", err)
}
}
用 excelize 解析上传的 Excel 文件(导入)
Beego 接收文件用 c.GetFile("file"),但返回的是 multipart.File(类似 *os.File),不能直接传给 excelize —— 它需要 io.ReadSeeker。常见错误是忽略 defer f.Close() 导致句柄泄漏,或未校验后缀名导致解析失败。
- 必须检查文件后缀是否为
.xlsx,.xls不被 excelize 支持(需换tealeg/xlsx或转格式) - 用
f, err := excelize.OpenReader(file)加载,不是OpenFile - 读取前先用
f.GetSheetList()确认 sheet 名,避免硬编码"Sheet1"导致 panic - 空行、合并单元格、公式值需特殊处理:
f.GetCellValue()返回显示值,f.GetSheetMap()可查原始结构
func (c *ImportController) Post() {
f, h, err := c.GetFile("file")
if err != nil {
c.Data["json"] = map[string]string{"error": "no file uploaded"}
c.ServeJSON()
return
}
defer f.Close()
if filepath.Ext(h.Filename) != ".xlsx" {
c.Data["json"] = map[string]string{"error": "only .xlsx supported"}
c.ServeJSON()
return
}
xlsx, err := excelize.OpenReader(f)
if err != nil {
c.Data["json"] = map[string]string{"error": "invalid xlsx format"}
c.ServeJSON()
return
}
rows, err := xlsx.GetRows("Sheet1")
if err != nil {
beego.Warn("GetRows failed:", err)
}
// 处理 rows...
}
真正容易被忽略的点是:excelize 默认不校验 Excel 内容合法性(比如非法字符、超长字符串),导入时若不做字段长度/类型校验,可能静默截断或入库失败;导出时若未调用 f.SaveAs() 或 f.WriteTo() 之外的任何方法,f.Bytes() 可能返回空切片 —— 这些都不会报错,只会让你花半小时对着空白下载文件发呆。











