Files
x_admin/server/util/excel2/excel_import.go
2024-08-12 02:25:15 +08:00

177 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package excel2
import (
"bytes"
"errors"
"fmt"
"io"
"mime/multipart"
"reflect"
"strconv"
"github.com/xuri/excelize/v2"
)
func GetExcelData(file multipart.File, dst interface{}) (err error) {
// 创建缓冲区
buf := new(bytes.Buffer)
// 将文件内容复制到缓冲区
_, err = io.Copy(buf, file)
if err != nil {
fmt.Println(err)
// c.String(http.StatusInternalServerError, "读取失败")
err = errors.New("读取失败")
return
}
// 创建Excel文件对象
f, err := excelize.OpenReader(bytes.NewReader(buf.Bytes()))
if err != nil {
fmt.Println(err)
// c.String(http.StatusInternalServerError, "Excel读取失败")
err = errors.New("Excel读取失败")
return
}
err = ImportExcel(f, dst, 1, 2)
// if err != nil {
// fmt.Println(err)
// }
return err
}
// ImportExcel 导入数据单个sheet
// 需要在传入的结构体中的字段加上tagexcel:"title:列头名称;"
// f 获取到的excel对象、dst 导入目标对象【传指针】
// headIndex 表头的索引从0开始用于获取表头名字
// startRow 头行行数从第startRow+1行开始扫
func ImportExcel(f *excelize.File, dst interface{}, headIndex, startRow int) (err error) {
sheetName := f.GetSheetName(0) // 单个sheet时默认读取第一个sheet
err = importData(f, dst, sheetName, headIndex, startRow)
return
}
// ImportBySheet 导入数据读取指定sheetsheetName Sheet名称
func ImportBySheet(f *excelize.File, dst interface{}, sheetName string, headIndex, startRow int) (err error) {
// 当需要读取多个sheet时可以通过下面的方式来调用 ImportBySheet 这个函数
//sheetList := f.GetSheetList()
//for _, sheetName := range sheetList {
// ImportBySheet(f,dst,sheetName,headIndex,startRow)
//}
err = importData(f, dst, sheetName, headIndex, startRow)
return
}
// 获取在数组中得下标
func GetIndex(items []string, item string) int {
for i, v := range items {
if v == item {
return i
}
}
return -1
}
// 判断数组中是否包含指定元素
// func IsContain(items interface{}, item interface{}) bool {
// switch items.(type) {
// case []int:
// intArr := items.([]int)
// for _, value := range intArr {
// if value == item.(int) {
// return true
// }
// }
// case []string:
// strArr := items.([]string)
// for _, value := range strArr {
// if value == item.(string) {
// return true
// }
// }
// default:
// return false
// }
// return false
// }
// 解析数据
func importData(f *excelize.File, dst interface{}, sheetName string, headIndex, startRow int) (err error) {
rows, err := f.GetRows(sheetName) // 获取所有行
if err != nil {
err = errors.New(sheetName + "工作表不存在")
return
}
dataValue := reflect.ValueOf(dst) // 取目标对象的元素类型、字段类型和 tag
// 判断数据的类型
if dataValue.Kind() != reflect.Ptr || dataValue.Elem().Kind() != reflect.Slice {
err = errors.New("invalid data type")
}
heads := []string{} // 表头
dataType := dataValue.Elem().Type().Elem() // 获取导入目标对象的类型信息
// 遍历行,解析数据并填充到目标对象中
for rowIndex, row := range rows {
if rowIndex == headIndex {
heads = row
}
if rowIndex < startRow { // 跳过头行
continue
}
newData := reflect.New(dataType).Elem() // 创建新的目标对象
// 遍历目标对象的字段
for i := 0; i < dataType.NumField(); i++ {
// 这里要用构造函数构造函数里指定了Index默认值为-1当目标结构体的tag没有指定index的话那么 excelTag.Index 就一直为0
// 那么 row[excelizeIndex] 就始终是 row[0],始终拿的是第一列的数据
var excelTag = NewExcelTag()
field := dataType.Field(i) // 获取字段信息和tag
tag := field.Tag.Get(ExcelTagKey)
if tag == "" { // 如果tag不存在则跳过
continue
}
err = excelTag.GetTag(tag)
if err != nil {
return
}
cellValue := ""
if excelTag.Index >= 0 { // 当tag里指定了index时根据这个index来拿数据
excelizeIndex := excelTag.Index // 解析tag的值
if excelizeIndex >= len(row) { // 防止下标越界
continue
}
cellValue = row[excelizeIndex] // 获取单元格的值
} else { // 否则根据表头名称来拿数据
var index = GetIndex(heads, excelTag.Name)
if index != -1 {
if index >= len(row) { // 防止下标越界
continue
}
cellValue = row[index] // 获取单元格的值
}
}
fmt.Println("Type.Name:", field.Type.Name(), field.Type.Kind())
// 根据字段类型设置值
switch field.Type.Kind() {
case reflect.Int:
v, _ := strconv.ParseInt(cellValue, 10, 64)
newData.Field(i).SetInt(v)
case reflect.Int64:
v, _ := strconv.ParseInt(cellValue, 10, 64)
newData.Field(i).SetInt(v)
case reflect.Uint:
v, _ := strconv.ParseUint(cellValue, 10, 64)
newData.Field(i).SetUint(v)
case reflect.Uint8:
v, _ := strconv.ParseUint(cellValue, 10, 64)
newData.Field(i).SetUint(v)
case reflect.Uint16:
v, _ := strconv.ParseUint(cellValue, 10, 64)
newData.Field(i).SetUint(v)
case reflect.String:
newData.Field(i).SetString(cellValue)
}
}
// 将新的目标对象添加到导入目标对象的slice中
dataValue.Elem().Set(reflect.Append(dataValue.Elem(), newData))
}
return
}