- struct支持导出为excel
- excel导入为struct
- 表头支持扩展,如:日期表头不确定长度
- excel第一行为备注
- excel表头进行汇总
- 标记某行为特殊颜色
- 如果字段为空,就不生成该表头
- 支持http响应
- 支持grpc响应
表头不支持重复
实际效果:
go get github.com/douyacun/go-struct-excel
package main type foo struct { Name string `excel:"姓名" json:"name"` Age *int `excel:"年龄,allowempty" json:"age"` Height int `excel:"身高,font{color:ff0000 size:16}" json:"height"` Holiday map[string]bool `excel:"假期,expand:regexp(^\\d{4}-\\d{2}-\\d{2}$)" json:"holiday"` } func (f foo) GatherHeaderRows() int { return 1 } func (f foo) GatherHeader(sheet *Sheet) error { style, _ := sheet.GetCenterStyle() headerLine := "7" sheet.Excel.SetCellValue(sheet.SheetName, "A"+headerLine, "个人信息") sheet.Excel.MergeCell(sheet.SheetName, "A"+headerLine, "C"+headerLine) sheet.Excel.SetCellStyle(sheet.SheetName, "A"+headerLine, "C"+headerLine, style) sheet.Excel.SetCellValue(sheet.SheetName, "D"+headerLine, "假期信息") sheet.Excel.MergeCell(sheet.SheetName, "D"+headerLine, "I"+headerLine) return nil } func (f foo) Remarks() (string, int, int) { return `.特别注意:导入数值加逗号格式,很经常被Excel带成数值,可在前面加个'号,或设置单元格格式为文本 .导入规则: .全局名称不允许重复 .各种包含类型枚举:可为空表示不定向,或输入:不限、包含、不包含 `, 6, 9 }
测试:
package main func TestNewExcel(t *testing.T) { excel := NewExcel("helloworld.xlsx") defer excel.File.Close() data := make([]*foo, 0) age := 28 data = append(data, &foo{ Name: "h", Age: &age, Height: 181, Holiday: map[string]bool{ "2022-01-27": false, "2022-01-28": true, "2022-01-29": true, }, }, &foo{ Name: "o", Age: &age, Height: 182, Holiday: map[string]bool{ "2022-01-27": true, "2022-01-28": true, "2022-01-30": true, "2022-02-09": true, "2022-12-09": true, }, }) if err := excel.AddSheet("hello").AddData(data); err != nil { t.Error(err) return } if err := excel.SaveAs(); err != nil { t.Errorf("文件保存失败: %s", err.Error()) return } dir, _ := os.Getwd() fmt.Println("当前路径:", dir) return }
http访问直接下载excel:
if err := excel.Response(ctx.Writer); err != nil { ctx.JSON(http.StatusOK, gin.H{"code": http.StatusBadRequest, "message": err.Error()}) }
grpc响应:
// 定义protobuf syntax = "proto3"; option go_package = "douyacun/proto/common;common"; package common; message ExcelFile { string filename = 1; bytes raw = 2; } message ExcelResponse { int32 code = 1; string error_message = 2; ExcelFile data = 3; }
如果是http代理grpc服务,可以通过类型断言:ExcelResponse
package main import "context" func handler(ctx context.Context) error { switch resp.(type) { case *commonProto.ExcelResponse: return response(ctx.writer, resp.(*commonProto.ExcelResponse)) default: return defaultHandle(ctx, req, resp) } } func response(w http.ResponseWriter) error { header := w.Header() byt, err := e.Bytes() if err != nil { return err } header["Accept-Length"] = []string{strconv.Itoa(len(byt))} header["Content-Type"] = []string{"application/vnd.ms-excel"} header["Access-Control-Expose-Headers"] = []string{"Content-Disposition"} header["Content-Disposition"] = []string{fmt.Sprintf("attachment; filename=\"%s\"", e.Filename)} w.Write(byt) return nil }
excel tag说明:
- tag英文逗号分隔,第一个作为表头名称,其他没有顺序要求
allowempty: 表头在场景一中需要展示,其他不需要。字段为指针类型,tag标记为allowmeptyfont: 设定此列富文本样式,支持{color:ff0000 size:16 italic:true blod:true underline:true}expand: 自动扩展表头,支持正则匹配表头,expand:regexp(^\\d{4}-\\d{2}-\\d{2}$)", 其中内置正则expand:date: 2022年06月18日expand:datetime: 2022年06月18日 08:27:39expand:month: 2022-06
表头备注:
type ExcelRemarks interface { Remarks() (remark string, row, col int) // 占用几行几列 }
汇总表头
package main type ExcelGatherHeader interface { GatherHeaderRows() int // 汇总表头占几行,不包括字段行 GatherHeader(sheet *Sheet) error // 汇总表头合并单元格,单元格样式需要自己实现 }
package main func TestReadData(t *testing.T) { excel, err := OpenExcel("helloword.xlsx") if err != nil { t.Error(err) } sheet, err := excel.OpenSheet("hello") if err != nil { t.Error(err) } if data, err := sheet.ReadData(foo{}); err != nil { t.Error(err) } else if d, ok := data.([]*foo); ok { if str, err := json.Marshal(d); err != nil { t.Error(err) } else { fmt.Println(string(str)) } } }
输出:
=== RUN TestReadData
[{"name":"h","age":28,"height":181,"holiday":{"2022年01月27日":false,"2022年01月28日":true,"2022年01月29日":true}},{"name":"o","age":28,"height":182,"holiday":{"2022年01月27日":true,"2022年01月28日":true,"2022年01月29日":false,"2022年01月30日":true,"2022年02月09日":true,"2022年12月09日":true}}]
--- PASS: TestReadData (0.00s)
PASS