golang 导出excel表格的两个包使用对比

第一种方法

项目地址:https://github.com/tealeg/xlsx

go get -u github.com/tealeg/xlsx

func test1() {

	// rows 为查询出的多条记录

	filename := fmt.Sprintf(test1.%d.xlsx", time.Now().Unix())

	type item struct {
		Rank         int
		Userid       int
		UserName     string
		NickName     string
		Phone        string
		Departid     int
		FirstDepart  string
		SecondDepart string
		ThirdDepart  string
		Score        int
		Update       string
	}

	list := make([]item, 0)
	var rk = 1
	var userid int
	var award_value int
	var createat int

	for rows.Next() {
		rows.Scan(&userid, &award_value, &createat)
		it := item{
			Rank:   rk,
			Userid: userid,
			Score:  award_value,
			Update: time.Unix(int64(createat), 0).Format(os.Getenv("DATE_FORMAT_SECOND")),
		}
		list = append(list, it)
		rk++
	}

	file := xlsx.NewFile()
	sheet, _ := file.AddSheet("Sheet1")
	var row *xlsx.Row
	var cell *xlsx.Cell

	// 字段标题,和 item 字段一一对应
	headers := []string{"名称", "用户ID", "对接账号", "姓名", "电话", "部门ID", "一级部门", "二级部门", "三级部门", "总积分", "最后更新时间"}

	// 设置单元格宽度
	sheet.SetColWidth(len(headers)-1, len(headers)-1, 15)

	row = sheet.AddRow()
	row.SetHeightCM(1.5)
	// 第一行大标题
	cell = row.AddCell()

	// 合并单元格
	cell.Merge(len(headers), 0)
	// 设置单元格样式
	style := cell.GetStyle()
	style.Alignment = xlsx.Alignment{
		Horizontal: "center", // 水平居中
		Vertical:   "center", // 垂直居中
	}
	// 设置字体,大小
	style.Font = xlsx.Font{
		Size: 16,
		Name: "Calibri",
		Bold: true,
	}
	
	cell.SetStyle(style)
	cell.Value = "test1"

	row = sheet.AddRow()
	for _, v := range headers {
		cell = row.AddCell()

		style = cell.GetStyle()
		style.Font = xlsx.Font{
			Size: 10,
			Name: "Calibri",
		}

		cell.Value = v
	}

	for _, v := range list {
		row = sheet.AddRow()

		getValue := reflect.ValueOf(v)
		n := getValue.NumField()
		for i := 0; i < n; i++ {
			cell = row.AddCell()

			// 设置单元格样式
			style = cell.GetStyle()
			style.Font = xlsx.Font{
				Size: 10,
				Name: "Calibri",
			}

			cell.SetStyle(style)

			val := getValue.Field(i)
			switch val.Kind() {
			case reflect.String:
				cell.Value = val.Interface().(string)
			case reflect.Int:
				cell.Value = strconv.Itoa(val.Interface().(int))
			}
		}
	}

	err = file.Save("../../../storage/read3/" + filename)
	if err != nil {
		return err
	}
	return nil
}

大部分的时候我们会将结构体切片的数据写入表格,而且结构体又不能遍历,如果字段过多,那么写起来就很麻烦,并且调整起来也格外麻烦。

反射的话字段都要可导出的。
关于结构体切片的反射可以参考 https://blog.csdn.net/raoxiaoya/article/details/111182338

另外一种方法是360出品的

项目地址:https://github.com/360EntSecGroup-Skylar/excelize

go get -u github.com/360EntSecGroup-Skylar/excelize/v2

这个包使用起来可配置性很强。说明较为详细,说明大部分在方法的注释里面。

func test2() {

	// rows 为查询出的多条记录

	filename := fmt.Sprintf(test2.%d.xlsx", time.Now().Unix())

	type item struct {
		Rank         int
		Userid       int
		UserName     string
		NickName     string
		Phone        string
		Departid     int
		FirstDepart  string
		SecondDepart string
		ThirdDepart  string
		Score        int
		Update       string
	}

	list := make([]item, 0)
	var rk = 1
	var userid int
	var award_value int
	var createat int

	for rows.Next() {
		rows.Scan(&userid, &award_value, &createat)
		it := item{
			Rank:   rk,
			Userid: userid,
			Score:  award_value,
			Phone: "15919901990",
			Update: time.Unix(int64(createat), 0).Format(os.Getenv("DATE_FORMAT_SECOND")),
		}
		list = append(list, it)
		rk++
	}

	// 数据导出 start

	// 字段标题,和 item 字段一一对应
	headers := []string{"排名", "用户ID", "对接账号", "姓名", "电话", "部门ID", "一级部门", "二级部门", "三级部门", "总积分", "最后更新时间"}

	// 默认存在第一个工作簿是 Sheet1 首字母要大写,否则会报错。
	// 如果想额外的创建工作簿,可以使用,sheet2 := file.NewSheet("Sheet2"),工作簿的名称不区分大小写。
	// 如果有多个工作簿,可以使用 file.SetActiveSheet(index) 来指定打开文件时focus到哪个工作簿
	sheet1 := "Sheet1"
	file := excelize.NewFile()

	// 65 -> A
	ln := len(headers)
	character := ""
	if ln <= 26 {
		character = string(64 + ln)
	} else if ln <= 52 {
		character = "A" + string(64+ln-26)
	} else {
		character = "AA" + string(64+ln-52)
	}

	/* -------------------- 第一行大标题 -------------------- */

	// 设置行高
	err = file.SetRowHeight(sheet1, 1, 40)
	if err != nil {
		return err
	}

	// 合并单元格
	err = file.MergeCell(sheet1, "A1", character+"1")
	if err != nil {
		return err
	}

	// 设置单元格样式:对齐;字体,大小;单元格边框
	styleTitle, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"italic":false,"family":"Calibri","size":16,"color":"#000000"},"border":[{"type":"left","color":"#3FAD08","style":0},{"type":"top","color":"#3FAD08","style":0},{"type":"bottom","color":"#3FAD08","style":2},{"type":"right","color":"#3FAD08","style":0}]}`)
	err = file.SetCellStyle(sheet1, "A1", character+"1", styleTitle)
	if err != nil {
		return err
	}

	err = file.SetCellValue(sheet1, "A1", "test2")
	if err != nil {
		return err
	}

	/* -------------------- 字段标题 -------------------- */
	styleHeader, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":false,"italic":false,"family":"Calibri","size":10,"color":"#000000"}}`)
	err = file.SetCellStyle(sheet1, "A2", character+"2", styleHeader)
	if err != nil {
		return err
	}

	for k, v := range headers {
		chr := ""
		if k < 26 {
			chr = string(64 + k + 1)
		} else if k < 52 {
			chr = "A" + string(64+k+1-26)
		} else {
			chr = "AA" + string(64+k+1-52)
		}
		err = file.SetCellValue(sheet1, chr+"2", v)
		if err != nil {
			return err
		}
	}

	// 设置最后一列宽度
	err = file.SetColWidth(sheet1, "C", character, 20)
	if err != nil {
		return err
	}

	// 冻结窗口:冻结第一行和第二行
	err = file.SetPanes(sheet1, `{"freeze":true,"split":false,"x_split":0,"y_split":2}`)
	if err != nil {
		return err
	}

	///* -------------------- 填充行数据 -------------------- */

	line := 3
	for _, v := range list {
		lineChr := strconv.Itoa(line)
		// 设置样式
		err = file.SetCellStyle(sheet1, "A"+lineChr, character+lineChr, styleHeader)
		if err != nil {
			return err
		}

		// 反射获取数据
		getValue := reflect.ValueOf(v)
		n := getValue.NumField()
		for i := 0; i < n; i++ {
			val := getValue.Field(i)

			chr := ""
			if i < 26 {
				chr = string(64 + i + 1)
			} else if i < 52 {
				chr = "A" + string(64+i+1-26)
			} else {
				chr = "AA" + string(64+i+1-52)
			}

			err = file.SetCellValue(sheet1, chr+lineChr, val.Interface())
			if err != nil {
				return err
			}
		}

		line++
	}

	err = file.SaveAs("../../../storage/" + filename)
	if err != nil {
		return err
	}
	
	return nil
}

在这里插入图片描述
关于单元格边框的设置,比如 "border":[{"type":"left","color":"#3FAD08","style":0} 其中 style 为线的类型,在 styles.go 中有说明
在这里插入图片描述
最后基于这个样式简单封装了一个方法

func OutPutDataWithXLSX(list interface{}, headers []string, title string, filepath string, filename string) (err error) {
	// 创建目录结构
	err = file.CheckAndMakeDirAll(filepath)
	if err != nil {
		return err
	}

	filename = filepath + "/" + filename

	// 默认存在第一个工作簿是 Sheet1 首字母要大写,否则会报错。
	// 如果想额外的创建工作簿,可以使用,sheet2 := file.NewSheet("Sheet2"),工作簿的名称不区分大小写。
	// 如果有多个工作簿,可以使用 file.SetActiveSheet(index) 来指定打开文件时focus到哪个工作簿
	sheet1 := "Sheet1"
	f := excelize.NewFile()

	character := string(65 + len(headers) - 1)

	/* -------------------- 第一行大标题 -------------------- */

	// 设置行高
	err = f.SetRowHeight(sheet1, 1, 40)
	if err != nil {
		return err
	}

	// 合并单元格
	err = f.MergeCell(sheet1, "A1", character+"1")
	if err != nil {
		return err
	}

	// 设置单元格样式:对齐;字体,大小;单元格边框
	styleTitle, _ := f.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"italic":false,"family":"Calibri","size":16,"color":"#000000"},"border":[{"type":"left","color":"#3FAD08","style":0},{"type":"top","color":"#3FAD08","style":0},{"type":"bottom","color":"#3FAD08","style":2},{"type":"right","color":"#3FAD08","style":0}]}`)
	err = f.SetCellStyle(sheet1, "A1", character+"1", styleTitle)
	if err != nil {
		return err
	}

	err = f.SetCellValue(sheet1, "A1", title)
	if err != nil {
		return err
	}

	/* -------------------- 字段标题 -------------------- */
	styleHeader, _ := f.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":false,"italic":false,"family":"Calibri","size":10,"color":"#000000"}}`)
	err = f.SetCellStyle(sheet1, "A2", character+"2", styleHeader)
	if err != nil {
		return err
	}

	for k, v := range headers {
		err = f.SetCellValue(sheet1, string(65+k)+"2", v)
		if err != nil {
			return err
		}
	}

	// 设置最后一列宽度
	err = f.SetColWidth(sheet1, "C", character, 20)
	if err != nil {
		return err
	}

	// 冻结窗口:冻结第一行和第二行
	err = f.SetPanes(sheet1, `{"freeze":true,"split":false,"x_split":0,"y_split":2}`)
	if err != nil {
		return err
	}

	///* -------------------- 填充行数据 -------------------- */

	getValue := reflect.ValueOf(list)
	if getValue.Kind() != reflect.Slice {
		return errors.New("list must be slice")
	}
	length := getValue.Len()

	if length > 0 {
		line := 3
		for i := 0; i < length; i++ {
			value := getValue.Index(i)
			typel := value.Type()
			if typel.Kind() != reflect.Struct {
				return errors.New("list must be slice of struct")
			}

			lineChr := strconv.Itoa(line)
			// 设置样式
			err = f.SetCellStyle(sheet1, "A"+lineChr, character+lineChr, styleHeader)
			if err != nil {
				return err
			}

			n := value.NumField()
			for i := 0; i < n; i++ {
				val := value.Field(i)
				err = f.SetCellValue(sheet1, string(65+i)+lineChr, val.Interface())
				if err != nil {
					return err
				}
			}

			line++
		}
	}

	err = f.SaveAs(filename)
	if err != nil {
		return err
	}

	return nil
}

调用


filepath := "../../../storage/" + taskmodel.TaskCate
filename := fmt.Sprintf("test2.%d.xlsx", time.Now().Unix())
title := "test2"
headers := []string{"排名", "用户ID", "对接账号", "姓名", "电话", "部门ID", "一级部门", "二级部门", "三级部门", "总积分", "最后更新时间", "毫秒"}

err = util.OutPutDataWithXLSX(list, headers, title, filepath, filename)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值