前言
大家好,这里是符华~
关于excelize库实现excel导入导出封装,我已经写了两篇了,我想要的功能基本已经实现了,现在还差一个模板导出,这篇文章就来讲讲如何实现用模板导出excel。
前两篇:
【Go】excelize库实现excel导入导出封装(一),自定义导出样式、隔行背景色、自适应行高、动态导出指定列、动态更改表头
【Go】excelize库实现excel导入导出封装(二),基于map、多个sheet、多级表头、树形结构表头导出,横向、纵向合并单元格导出
根据模板导出excel,在开发中也是经常会遇到的一种导出方式。一想到模板导出,我自然而然就想到了Java里的 easypoi 框架。easypoi 呢在Java里面也是一个操作excel使用率很高的框架,然后这个框架的模板导出呢,是有设定模板指令的,就是下面这种:
用的时候就是这样:
填充数据就是把数据放到map里面,map的key对应模板里面设置的字段名(比如 name、sfz 这几个字段名),map的value就是我们要导出的结果值。
然后呢我就想,Go里面用模板导出应该也是用模板指令的吧?但是呢其实在 excelize 库中,它并不支持类似的模板指令,这么看来 excelize 库好像不支持用模板导出?那有啥办法可以实现这个功能?
欸嘿,还真有,只不过这个模板导出呢就和 excelize 没啥关系了,但因为是自己封装导入导出,那我就干脆把这个模板导出也一起封装进来、一起放到这个专栏系列里面了。
实现
excelize 虽然没有模板指令,但是Go标准库中的 text/template
和 html/template
包提供了强大的模板功能,所以我们本篇文章的实现也是基于 html/template
来实现的。
html/template
的模板指令和 easypoi
的模板指令有点类似,但细节上还是有很大差异的,具体使用用法可以看看这篇文章:Go语言标准库之html/template详解 。
我们可以使用 text/template
和 html/template
来解析模板,但是需要注意的是,这两个库并不能直接解析excel模板,它们只能解析文本格式的文件,不能解析二进制格式的文件。
所以用的时候,我们准备好了一个excel模板时,还需要将这个excel文件另存为xml文件。
有了xml文件也不能直接用,有些地方的数据可能需要处理一下,比如遍历list的时候,需要将 range 遍历放到正确的位置。
检查好之后,再使用 template.ParseFiles 函数解析这个xml文件,接下来就可以填充数据了。填充好后,将渲染模板并输出为excel文件。
准备模板
我们先准备好excel模板
然后再另存为xml文件
拿到xml文件后,先不要急着解析,先格式化一下进行检查,如果数据太多,我们按照关键字搜索
错误的位置:
改正的位置:
按照上面的方法检查并改正好之后,保存好,这样我们就可以开始解析这个xml模板了。
开始
// 模板导出
func ExportTemplate() {
// 准备结构体数据
var list = []Test{
{"fuhua", "符华", "fuhua@123.com", "太虚剑派", false, "1", 1},
{"baiye", "白夜", "baiye@123.com", "天命科技有限公司", false, "2", 1},
{"chiling", "炽翎", "chiling@123.com", "太虚剑派", false, "2", 2},
{"yunmo", "云墨", "yunmo@123.com", "太虚剑派", false, "1", 2},
{"yuelun", "月轮", "yuelun@123.com", "天命科技有限公司", false, "1", 1},
{"xunyu", "迅羽", "xunyu@123.com", "天命科技有限公司", true, "2", 124},
}
// 准备map数据
data := map[string]any{
"name": "符华",
"sex": "女",
"birthday": "2000-10-01",
"jg": "广东省",
"sfz": "123456789111111111",
"gzdw": "天命科技",
"email": "fuhua@123.com",
"phone": "13188888888",
"workList": []map[string]any{
{"date": "2019-01-01~2020-10-01", "unit": "逐火之蛾", "post": "普通员工", "sfzz": "否"},
{"date": "2020-10-20~2022-09-15", "unit": "太虚剑派", "post": "CEO", "sfzz": "否"},
{"date": "2022-10-01~至今", "unit": "天命科技", "post": "经理", "sfzz": "是"},
},
"list": list,
}
templatePath := "template\\测试模板导出.xml" // 模板路径
outPath := "C:\\Users\\Administrator\\Desktop\\output.xlsx" // 输出路径
err := excel.TemplateExport(templatePath, outPath, data)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("导出成功!")
// 将excel下载到浏览器,第一个参数是模板路径、第二个参数是下载的文件名称(要带上后缀)、第三个参数是模板数据、第四个参数是http响应
// excel.DownLoadByTemplate(templatePath,"output.xlsx",data,res)
}
excel 包下的 TemplateExport 函数:
// TemplateExport 基于excel的模板导出
func TemplateExport(templatePath, outPath string, data map[string]interface{}) error {
// 解析模板
tmpl, err := template.ParseFiles(templatePath)
if err != nil {
return errors.New("模板解析失败:" + err.Error())
}
// 创建输出文件
file, err := os.Create(outPath)
if err != nil {
return errors.New("创建输出文件失败:" + err.Error())
}
defer file.Close()
// 渲染模板并输出结果
err = tmpl.Execute(file, data)
if err != nil {
return errors.New("模板数据渲染失败:" + err.Error())
}
return nil
}
excel 包下的 DownLoadByTemplate 函数:
// 根据模板下载文件:templatePath 模板路径,fileName 文件名称(需要加上后缀名),data 模板数据
func DownLoadByTemplate(templatePath, fileName string, data map[string]interface{}, res http.ResponseWriter) {
// 解析模板
tmpl, err := template.ParseFiles(templatePath)
if err != nil {
http.Error(res, "模板解析失败:"+err.Error(), http.StatusInternalServerError)
return
}
// 设置响应头
res.Header().Set("Content-Type", "text/html; charset=UTF-8")
res.Header().Set("Content-Type", "application/octet-stream")
res.Header().Set("Content-Disposition", "attachment; filename="+fileName)
res.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
// 渲染模板并输出结果
err = tmpl.Execute(res, data)
if err != nil {
http.Error(res, "模板数据渲染失败:"+err.Error(), http.StatusInternalServerError)
}
}
导出结果:
这样子我们就实现了根据模板导出excel辣~
最后
这里是 源码
如果大家觉得本篇文章或专栏对你有所帮助或者觉得写得还可以的话,欢迎大家多多给博主 点赞
加 关注
支持一下哦😘下载源码的时候顺便给博主点个Star😘你动动手指就是对我莫大的鼓励🥰