当前位置:网站首页>Go 结合Gin导出Mysql数据到Excel表格
Go 结合Gin导出Mysql数据到Excel表格
2022-07-30 05:51:00 【行人已】
1、实现目标
Golang 使用excelize 导出表格到浏览器下载或者保存到本地。
后续导入的话也会写到这里
2、使用的库
go get github.com/xuri/excelize/v2
Git地址:
https://github.com/qax-os/excelize
文档地址:
https://xuri.me/excelize/zh-hans/base/installation.html#install
3、项目目录
go-excel
├─ app
│ ├─ excelize
│ │ └─ excelize.go
│ ├─ model
│ │ └─ sysUser.go
│ └─ service
│ └─ userService.go
├─ common
│ └─ mysql.go
├─ go.mod
├─ go.sum
├─ main.go
└─ setting.json
4、主要代码编写
gin还不会老师们可以看:https://blog.csdn.net/bei_FengBoby/article/details/124847078
读取配置文件是用的viper
4.1、excelize.go(主要工具类)
ExportExcelByStruct 函数 是从网络上直接copy的,研究他这个写法花了好一会儿,所以也写上去了,提供大家学习
import (
"fmt"
"math/rand"
"net/url"
"reflect"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
)
var (
defaultSheetName = "Sheet1" //默认Sheet名称
defaultHeight = 25.0 //默认行高度
)
type lzExcelExport struct {
file *excelize.File
sheetName string //可定义默认sheet名称
}
func NewMyExcel() *lzExcelExport {
return &lzExcelExport{file: createFile(), sheetName: defaultSheetName}
}
//导出基本的表格
func (l *lzExcelExport) ExportToPath(params []map[string]string, data []map[string]interface{}, path string) (string, error) {
l.export(params, data)
name := createFileName()
filePath := path + "/" + name
err := l.file.SaveAs(filePath)
return filePath, err
}
//导出到浏览器。此处使用的gin框架 其他框架可自行修改ctx
func (l *lzExcelExport) ExportToWeb(params []map[string]string, data []map[string]interface{}, c *gin.Context) {
l.export(params, data)
buffer, _ := l.file.WriteToBuffer()
//设置文件类型
c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
//设置文件名称
c.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(createFileName()))
_, _ = c.Writer.Write(buffer.Bytes())
}
//设置首行
func (l *lzExcelExport) writeTop(params []map[string]string) {
topStyle, _ := l.file.NewStyle(`{"font":{"bold":true},"alignment":{"horizontal":"center","vertical":"center"}}`)
var word = 'A'
//首行写入
for _, conf := range params {
title := conf["title"]
width, _ := strconv.ParseFloat(conf["width"], 64)
line := fmt.Sprintf("%c1", word)
//设置标题
_ = l.file.SetCellValue(l.sheetName, line, title)
//列宽
_ = l.file.SetColWidth(l.sheetName, fmt.Sprintf("%c", word), fmt.Sprintf("%c", word), width)
//设置样式
_ = l.file.SetCellStyle(l.sheetName, line, line, topStyle)
word++
}
}
//写入数据
func (l *lzExcelExport) writeData(params []map[string]string, data []map[string]interface{}) {
lineStyle, _ := l.file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}}`)
//数据写入
var j = 2 //数据开始行数
for i, val := range data {
//设置行高
_ = l.file.SetRowHeight(l.sheetName, i+1, defaultHeight)
//逐列写入
var word = 'A'
for _, conf := range params {
valKey := conf["key"]
line := fmt.Sprintf("%c%v", word, j)
isNum := conf["is_num"]
//设置值
if isNum != "0" {
valNum := fmt.Sprintf("'%v", val[valKey])
_ = l.file.SetCellValue(l.sheetName, line, valNum)
} else {
_ = l.file.SetCellValue(l.sheetName, line, val[valKey])
}
//设置样式
_ = l.file.SetCellStyle(l.sheetName, line, line, lineStyle)
word++
}
j++
}
//设置行高 尾行
_ = l.file.SetRowHeight(l.sheetName, len(data)+1, defaultHeight)
}
func (l *lzExcelExport) export(params []map[string]string, data []map[string]interface{}) {
l.writeTop(params)
l.writeData(params, data)
}
func createFile() *excelize.File {
f := excelize.NewFile()
// 创建一个默认工作表
sheetName := defaultSheetName
index := f.NewSheet(sheetName)
// 设置工作簿的默认工作表
f.SetActiveSheet(index)
return f
}
func createFileName() string {
name := time.Now().Format("2006-01-02-15-04-05")
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("excle-%v-%v.xlsx", name, rand.Int63n(time.Now().Unix()))
}
//excel导出(数据源为Struct) []interface{}
func (l *lzExcelExport) ExportExcelByStruct(titleList []string, data []interface{}, fileName string, sheetName string, c *gin.Context) error {
l.file.SetSheetName("Sheet1", sheetName)
header := make([]string, 0)
for _, v := range titleList {
header = append(header, v)
}
rowStyleID, _ := l.file.NewStyle(`{"font":{"color":"#666666","size":13,"family":"arial"},"alignment":{"vertical":"center","horizontal":"center"}}`)
_ = l.file.SetSheetRow(sheetName, "A1", &header)
_ = l.file.SetRowHeight("Sheet1", 1, 30)
length := len(titleList)
headStyle := Letter(length)
var lastRow string
var widthRow string
for k, v := range headStyle {
if k == length-1 {
lastRow = fmt.Sprintf("%s1", v)
widthRow = v
}
}
if err := l.file.SetColWidth(sheetName, "A", widthRow, 30); err != nil {
fmt.Print("错误--", err.Error())
}
rowNum := 1
for _, v := range data {
t := reflect.TypeOf(v)
fmt.Print("--ttt--", t.NumField())
value := reflect.ValueOf(v)
row := make([]interface {
}, 0)
for l := 0; l < t.NumField(); l++ {
val := value.Field(l).Interface()
row = append(row, val)
}
rowNum++
err := l.file.SetSheetRow(sheetName, "A"+strconv.Itoa(rowNum), &row)
_ = l.file.SetCellStyle(sheetName, fmt.Sprintf("A%d", rowNum), fmt.Sprintf("%s", lastRow), rowStyleID)
if err != nil {
return err
}
}
disposition := fmt.Sprintf("attachment; filename=%s.xlsx", url.QueryEscape(fileName))
c.Writer.Header().Set("Content-Type", "application/octet-stream")
c.Writer.Header().Set("Content-Disposition", disposition)
c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
return l.file.Write(c.Writer)
}
// Letter 遍历a-z
func Letter(length int) []string {
var str []string
for i := 0; i < length; i++ {
str = append(str, string(rune('A'+i)))
}
return str
}
4.2、userService.go(接受请求)
其中导出的函数都已经测试是ok的,可以直接用,数据改成自己的就好,
注意的事项里面我也写了,避雷!!
import (
"go-excel/app/excelize"
"go-excel/app/model"
config "go-excel/common"
"github.com/gin-gonic/gin"
)
//获取所有用户数据-excel
func GetAllUserExportToWeb(ctx *gin.Context) {
var users []model.TUser
db := config.GetDB()
db.Find(&users)
//定义首行标题
dataKey := make([]map[string]string, 0)
dataKey = append(dataKey, map[string]string{
"key": "id",
"title": "索引",
"width": "20",
"is_num": "0",
})
dataKey = append(dataKey, map[string]string{
"key": "username",
"title": "用户名",
"width": "20",
"is_num": "0",
})
dataKey = append(dataKey, map[string]string{
"key": "remark",
"title": "备注",
"width": "20",
"is_num": "0",
})
//填充数据
data := make([]map[string]interface{}, 0)
if len(users) > 0 {
for _, v := range users {
data = append(data, map[string]interface{}{
"id": v.ID,
"username": v.Username,
"remark": v.Remark,
})
}
}
ex := excelize.NewMyExcel()
// ex.ExportToWeb(dataKey, data, ctx)
//保存到D盘
ex.ExportToPath(dataKey, data, "D:/")
}
//excel 导出
func GetUserExcelByMap(ctx *gin.Context) {
var users []model.TUser
db := config.GetDB()
db.Find(&users)
titles := []string{"ID", "用户名", "备注"}
ex := excelize.NewMyExcel()
var datas []interface{}
for _, v := range users {
//这里最好新建一个struct 和titles一致,不然users里面的多余的字段也会写进去
datas = append(datas, model.TUser{
ID: v.ID,
Username: v.Username,
Remark: v.Remark,
})
}
ex.ExportExcelByStruct(titles, datas, "用户数据", "用户", ctx)
}
4.2、测试结果
GetAllUserExportToWeb

GetUserExcelByMap

5、文档代码地址
https://gitee.com/hjx_RuGuoYunZhiDao/strom-huang-go.git —go-excel目录
边栏推荐
- 空间顶点到平面的距离计算的证明及其源码
- LVM and disk quotas
- 2020 数学建模之旅
- New material under the plastic restriction order - polylactic acid (PLA)
- Redis下载与安装
- @Bean 与 @Component 用在同一个类上,会怎样?
- Redis download and installation
- 识别“数据陷阱”,发现数据的可疑之处
- Calculate the inverse source of the matrix (using the adjoint matrix, a 3x3 matrix)
- (GGG)JWT
猜你喜欢

numpy 多维数组ndarray的详解

向量叉乘的几何意义及其模的计算

Is it possible to use the same port for UDP and TCP?

(GGG)JWT

Data types of Redis6

Process and Scheduled Task Management

不会吧,Log4j 漏洞还没有完全修复?

What happens when @Bean and @Component are used on the same class?

从追赶到超越,国产软件大显身手

相机坐标系,世界坐标系,像素坐标系三者转换,以及OPENGLDEFocal Length和Opengl 的 Fov转换
随机推荐
《心智社会》—马文·明斯基
AI can identify race from X-rays, but no one knows why
空间直线到平面上的交点的计算证明及其源码
Redis下载与安装
向量的导数运算和向量叉乘以及点乘的导数运算
删除openstack中的僵尸实例
Is it possible to use the same port for UDP and TCP?
阿里二面:Sentinel vs Hystrix 对比,如何选择?
Proftpd配置文件
The CTO said I was not advised to use SELECT *, why is that?
What happens when @Bean and @Component are used on the same class?
The calculation of the determinant of the matrix and its source code
进程和计划任务管理
人工肌肉智能材料新突破
STL source code analysis: conceptual understanding of iterators, and code testing.
开发常用工具软件
Redis 如何实现防止超卖和库存扣减操作?
Table with tens of millions of data, how to query the fastest?
window.open()的用法,js打开新窗体
MySQL主从复制配置搭建,一步到位