当前位置: 首页 > news >正文

【Go】excelize库实现excel导入导出封装(三),基于excel模板导出excel

前言

大家好,这里是符华~

关于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/templatehtml/template 包提供了强大的模板功能,所以我们本篇文章的实现也是基于 html/template 来实现的。

html/template 的模板指令和 easypoi 的模板指令有点类似,但细节上还是有很大差异的,具体使用用法可以看看这篇文章:Go语言标准库之html/template详解 。

我们可以使用 text/templatehtml/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😘你动动手指就是对我莫大的鼓励🥰

相关文章:

  • Linux shell编程学习笔记39:df命令
  • Go语言使用gosseract 库来进行图像文字识别,识别出来的中文是乱码的?如何解决?
  • linux项目部署(jdk,tomcat,mysql,nginx,redis)
  • python学习笔记10(选择结构2、循环结构1)
  • 【Linux】Linux系统编程——Linux目录结构
  • 【驱动】TI AM437x(内核调试-02):dynamic 动态打印调试
  • 微信小程序Canvas画布绘制图片、文字、矩形、(椭)圆、直线
  • Spring整理-Spring框架的国际化
  • 根据gbt81702008数值修约的C#函数
  • Logstash:迁移数据到 Elasticsearch
  • MySQL 8.0中新增的功能(八)
  • Python+甘特图及标签设置
  • 计算机网络层之ICMP与IGMP
  • 已解决java.lang.NoSuchFieldException异常的正确解决方法,亲测有效!!!
  • Python 网络爬虫入门详解
  • @angular/forms 源码解析之双向绑定
  • express + mock 让前后台并行开发
  • Laravel 菜鸟晋级之路
  • Promise面试题,控制异步流程
  • Python进阶细节
  • Theano - 导数
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 机器学习 vs. 深度学习
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 提醒我喝水chrome插件开发指南
  • 微信小程序设置上一页数据
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • Java数据解析之JSON
  • Mac 上flink的安装与启动
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • # .NET Framework中使用命名管道进行进程间通信
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #微信小程序:微信小程序常见的配置传值
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • $.ajax,axios,fetch三种ajax请求的区别
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (4) PIVOT 和 UPIVOT 的使用
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (三)终结任务
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)VC++中ondraw在什么时候调用的
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .gitattributes 文件
  • .NET 8.0 发布到 IIS
  • .NET Core 版本不支持的问题
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .net下简单快捷的数值高低位切换
  • ::什么意思
  • ??javascript里的变量问题
  • @Autowired和@Resource的区别
  • @property python知乎_Python3基础之:property
  • [ C++ ] STL---stack与queue