使用golang导出excel
Contents
原因
在日常开发中,经常会遇到要导出数据excel的需求,而go 的强类型就导致数据转换不是很方便。下面记录下我自己最近做的一个小需求,导出数据库某个model所有数据。使用golang 的反射和excel处理模块excelize
数据定义
type ExportData struct {
ID string `json:"id" title:"序号" column:"A"`
Ip string `json:"ip" title:"IP" column:"B"`
BlockTime string `json:"block_time" title:"封禁时间" column:"C"`
BlockMode string `json:"block_mode" title:"封禁方式" column:"D"`
UnblockTime string `json:"unblock_time,omitempty" title:"解封时间" column:"E"`
UnblockMode string `json:"unblock_mode,omitempty" title:"解封方式" column:"F"`
Fw string `json:"fw" title:"防火墙" column:"G"`
}
这里我们为每一个字段加上的tag 加上自定义的tag,title 代表表头的字段,column 代表在excel 的那一列,后面可以用反射取出来拼接数据
生成表头和设置格式
const (
CurrentBlock = "当前封禁"
HistoryBlock = "历史记录"
)
func initFile() (*excelize.File, error) {
var export ExportData
types := reflect.TypeOf(export)
f := excelize.NewFile()
f.SetSheetName("Sheet1", CurrentBlock)
current := f.GetSheetIndex(CurrentBlock)
history := f.NewSheet(HistoryBlock)
for i := 0; i < types.NumField(); i++ {
title := types.Field(i).Tag.Get("title")
column := types.Field(i).Tag.Get("column")
var headerRow = 1
strId := strconv.FormatInt(int64(headerRow), 10)
if i < 4 {
if err := f.SetCellValue(CurrentBlock, column+strId, title); err != nil {
return nil, err
}
}
if err := f.SetCellStr(HistoryBlock, column+strId, title); err != nil {
return nil, err
}
}
f.SetActiveSheet(history)
f.SetActiveSheet(current)
return f, nil
}
根据定义的title 生成表头,并且通过column指定写入的行数
写入数据
这里因为业务需求,有两个sheet,字段有区别 所以要处理写入的column
func whiteXlsxFile(record []ExportData, unblock bool, file *excelize.File) (*excelize.File, error) {
types := reflect.TypeOf(ExportData{})
fieldLength := types.NumField()
for i, row := range record {
values := reflect.ValueOf(row)
// 使用不同的sheet
var sheet = CurrentBlock
if unblock {
sheet = HistoryBlock
}
for j := 0; j < fieldLength; j++ {
column := types.Field(j).Tag.Get("column")
val := parseBlockMode(values.Field(j).String())
if unblock {
// 当前解禁只写到D列
if column == "E" && !unblock {
break
}
}
idCell := fmt.Sprintf("A%d", i+2) // i+2 跳过表头
cell := fmt.Sprintf("%s%d", column, i+2)
if err := file.SetCellStr(sheet, idCell, fmt.Sprintf("%d", i+1)); err != nil {
return nil, err
}
if err := file.SetCellStr(sheet, cell, val); err != nil {
return nil, err
}
}
}
return file, nil
}
写入响应
writer :=http.ResponseWriter // 换成自己的writer
writer.Header().Set("Content-Disposition", `attachment; filename="文件名称.xlsx";`)
writer.WriteHeader(200)
file, err := utils.GenXlsxFile(res, historyRecord)
if err != nil {
return err
}
if _, err := file.WriteTo(writer); err != nil {
return err
}