编程式导入导出

This commit is contained in:
xiangheng
2024-08-12 19:15:47 +08:00
parent bc059cd05f
commit c1b3b91e32
4 changed files with 101 additions and 144 deletions

View File

@@ -6,13 +6,12 @@ import (
"fmt"
"io"
"mime/multipart"
"reflect"
"strconv"
"x_admin/util"
"github.com/xuri/excelize/v2"
)
func GetExcelData(file multipart.File, dst interface{}) (err error) {
func GetExcelData(file multipart.File, dst interface{}, cols []Col) (err error) {
// 创建缓冲区
buf := new(bytes.Buffer)
@@ -32,7 +31,7 @@ func GetExcelData(file multipart.File, dst interface{}) (err error) {
err = errors.New("Excel读取失败")
return
}
err = ImportExcel(f, dst, 1, 2)
err = ImportExcel(f, dst, 2, cols)
// if err != nil {
// fmt.Println(err)
// }
@@ -44,20 +43,20 @@ func GetExcelData(file multipart.File, dst interface{}) (err error) {
// f 获取到的excel对象、dst 导入目标对象【传指针】
// headIndex 表头的索引从0开始用于获取表头名字
// startRow 头行行数从第startRow+1行开始扫
func ImportExcel(f *excelize.File, dst interface{}, headIndex, startRow int) (err error) {
func ImportExcel(f *excelize.File, dst interface{}, startRow int, cols []Col) (err error) {
sheetName := f.GetSheetName(0) // 单个sheet时默认读取第一个sheet
err = importData(f, dst, sheetName, headIndex, startRow)
err = importData(f, dst, sheetName, startRow, cols)
return
}
// ImportBySheet 导入数据读取指定sheetsheetName Sheet名称
func ImportBySheet(f *excelize.File, dst interface{}, sheetName string, headIndex, startRow int) (err error) {
func ImportBySheet(f *excelize.File, dst interface{}, sheetName string, startRow int, cols []Col) (err error) {
// 当需要读取多个sheet时可以通过下面的方式来调用 ImportBySheet 这个函数
//sheetList := f.GetSheetList()
//for _, sheetName := range sheetList {
// ImportBySheet(f,dst,sheetName,headIndex,startRow)
// ImportBySheet(f,dst,sheetName,startRow)
//}
err = importData(f, dst, sheetName, headIndex, startRow)
err = importData(f, dst, sheetName, startRow, cols)
return
}
@@ -71,106 +70,69 @@ func GetIndex(items []string, item string) int {
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) {
func importData(f *excelize.File, dst interface{}, sheetName string, startRow int, cols []Col) (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 { // 跳过头行
// heads := []string{}
var data = []map[string]interface{}{}
for i := 0; i < len(rows); i++ {
if i < 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] // 获取单元格的值
var rowMap = map[string]interface{}{}
for j := 0; j < len(cols); j++ {
col := cols[j]
key := col.Key
replace := col.Replace
val := rows[i][j]
// 将val替换为key
for replaceKey, v := range replace {
if fmt.Sprintf("%v", v) == fmt.Sprintf("%v", val) {
val = fmt.Sprintf("%v", replaceKey)
break
}
}
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)
if col.Decode != nil {
rowMap[key] = col.Decode(val)
} else {
rowMap[key] = val
}
}
// 将新的目标对象添加到导入目标对象的slice中
dataValue.Elem().Set(reflect.Append(dataValue.Elem(), newData))
data = append(data, rowMap)
}
util.ConvertUtil.MapToStruct(data, dst)
// 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)
// }
return
}