说明

本人在完成WeJH的一个接口开发后,完成了此文章的撰写

用了什么就写什么,剩余的如果在后续开发中用到,会在博客中补充

具体实现在文末

准备

使用excelize.官方文档传送门 github库传送门)

1
go get github.com/xuri/excelize/v2

开发

本次采用流式写入(用于向已存在的空白工作表写入大规模数据)

获取流式写入器

1
func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error)

按行流式写入工作表

1
func (sw *StreamWriter) SetRow(cell string, values []interface{}, opts ...RowOpts) error

流式合并单元格

1
func (sw *StreamWriter) MergeCell(topLeftCell, bottomRightCell string) error

流式设置列宽度

1
func (sw *StreamWriter) SetColWidth(min, max int, width float64) error

结束流式写入

1
func (sw *StreamWriter) Flush() error

创建样式

1
func (f *File) NewStyle(style *Style) (int, error)

样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Alignment 映射单元格对齐样式设置。
type Alignment struct {
Horizontal string
Indent int
JustifyLastLine bool
ReadingOrder uint64
RelativeIndent int
ShrinkToFit bool
TextRotation int
Vertical string
WrapText bool
}

Border 映射单元格边框样式设置。
type Border struct {
Type string
Color string
Style int
}

Font 映射字体样式设置。
type Font struct {
Bold bool
Italic bool
Underline string
Family string
Size float64
Strike bool
Color string
ColorIndexed int
ColorTheme *int
ColorTint float64
VertAlign string
}

Fill 映射单元格样式填充设置。
type Fill struct {
Type string
Pattern int
Color []string
Shading int
}

Protection 映射保护单元格属性设置。
type Protection struct {
Hidden bool
Locked bool
}

Style 映射单元格样式设置。
type Style struct {
Border []Border
Fill Fill
Font *Font
Alignment *Alignment
Protection *Protection
NumFmt int
DecimalPlaces int
CustomNumFmt *string
NegRed bool
}

具体思路

获取流式写入器->设置表头->设置样式->设置每列名->批量导入数据->调整列宽->结束流式写入

具体代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

type GetExcelData struct {
Campus uint8 `form:"campus" binding:"required"`
}

// 导出为excel文件
func ExportSuppliesRecord(c *gin.Context) {
//接受query参数
var data GetExcelData
err := c.ShouldBindQuery(&data)
if err != nil {
fmt.Println(err)
return
}

//根据参数获取数据库里指定的数据
ExcelData, err := suppliesServices.GetExcelData(*publisher, data.Campus)
if err != nil {
fmt.Println(err)
return
}

//将数据库里的数字转换为容易理解的文字
campusMap := map[uint8]string{
}
statusMap := map[int]string{
}

// 创建Excel文件
f := excelize.NewFile()
//获取Sheet1的流式写入器
streamWriter, err := f.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
return
}
//设置列宽,即A列到T列的宽度为15
if err := streamWriter.SetColWidth(1, 20, 15); err != nil {
fmt.Println(err)
return
}
//单独将E列加宽(因为E列要展示的数据比较长)
if err := streamWriter.SetColWidth(5, 5, 25); err != nil {
fmt.Println(err)
return
}
//设置样式
styleID, err := f.NewStyle(&excelize.Style{
//居中对齐
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
//颜色(浅蓝色),填充
Fill: excelize.Fill{Type: "pattern", Color: []string{"#DFEBF6"}, Pattern: 1},
})
if err != nil {
fmt.Println(err)
return
}
//表名
if err := streamWriter.SetRow("A1", []interface{}{
excelize.Cell{Value: "表名", StyleID: styleID},
}, excelize.RowOpts{Height: 30, Hidden: false}); err != nil {
fmt.Println(err)
return
}
//流式合并单元格
if err := streamWriter.MergeCell("A1", "P1"); err != nil {
fmt.Println(err)
return
}
//设置列名
header := []interface{}{}
for _, cell := range []string{
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
} {
header = append(header, cell)
}
if err := streamWriter.SetRow("A2", header); err != nil {
fmt.Println(err)
return
}
//批量导入数据
for rowID, record := range ExcelData {
campus, _ := campusMap[record.Campus]
status, _ := statusMap[record.Status]
result, err := suppliesServices.GetSuppliesById(record.SuppliesID)
if err != nil {
fmt.Println(err)
return
}
//将数据一一填入
row := []interface{}{
record.ID, record.Name, record.Gender, record.StudentID, record.College, record.Dormitory,
record.Contact, campus, result.Name, result.Kind, result.Spec, record.Count,
status, record.ApplyTime, record.BorrowTime, record.ReturnTime,
}
//是从第三行开始填数据,获取每行第一个索引
cell, _ := excelize.CoordinatesToCellName(1, rowID+3)
if err := streamWriter.SetRow(cell, row); err != nil {
fmt.Println(err)
return
}
}
//结束流式写入(不要忘了)
if err := streamWriter.Flush(); err != nil {
fmt.Println(err)
return
}
//保存Excel文件,文件名,保存的路径自由选择
fileName := uuid.NewString() + ".xlsx"
filePath := "./files/" + fileName
if err := f.SaveAs(filePath); err != nil {
fmt.Println(err)
return
}
}