add import

main
lj-wsdj 2024-06-20 15:33:14 +08:00
parent c4fa0fad1e
commit e9d6617baa
4 changed files with 181 additions and 1 deletions

View File

@ -1,6 +1,6 @@
# xlsx
excel的导出导入(目前仅完成导出)
excel的导出导入
## 导出功能
如果要使用导出则传入的数据必须为指针类型可以是struct或者元素为struct的slice。
@ -9,3 +9,10 @@ excel的导出导入目前仅完成导出
当导出的excel表格列数不确定时tag使用`export:"loop:true"`这样会将所有字段导出到excel表格中。
详情请看测试文件
## 导入功能
如果要使用导入则传入的数据必须为指针类型是元素为struct的slice。
通过tag来确认需要导入的字段内容为`import:"index:1"`index为excel表格中的列数从1开始。当需要导入的数据为日期时结构体中必须为time.Time类型不可以用自定义的日期类型且excel表格中的日期格式必须为yyyy-mm-dd或yyyy-mm-dd hh:mm:ss。
详细请看测试文件

31
import1_test.go 100644
View File

@ -0,0 +1,31 @@
package xlsx
import (
"fmt"
"testing"
"time"
"git.botann.com/lijun/xlsx/imports"
)
type Data struct {
Autoseq int
Name string `import:"true,index:1"`
Unit string `import:"true,index:2"`
TestCol string
Invest int64 `import:"true,index:3"`
CreateTime time.Time `import:"true,index:4"`
}
func TestMain(t *testing.T) {
var data []Data
importer, err := imports.NewFileImporter("./test7.xlsx", &data)
if err != nil {
fmt.Println(err)
}
err = importer.Import(0)
if err != nil {
fmt.Println(err)
}
fmt.Println(data)
}

142
imports/xlsx.go 100644
View File

@ -0,0 +1,142 @@
package imports
import (
"fmt"
"io"
"reflect"
"strconv"
"strings"
"time"
"github.com/xuri/excelize/v2"
)
type Importer struct {
Reader io.Reader
Sheets []string
xlsxFile *excelize.File
Data interface{}
}
func NewFileImporter(file string, data any) (*Importer, error) {
f, err := excelize.OpenFile(file)
if err != nil {
return nil, err
}
sheets := f.GetSheetList()
return &Importer{
xlsxFile: f,
Sheets: sheets,
Data: data,
}, nil
}
func NewFileReaderImporter(reader io.Reader, data any) (*Importer, error) {
f, err := excelize.OpenReader(reader)
if err != nil {
return nil, err
}
sheets := f.GetSheetList()
return &Importer{
xlsxFile: f,
Sheets: sheets,
Data: data,
}, nil
}
func (i *Importer) Import(sheetIndex int) error {
v := reflect.ValueOf(i.Data)
if v.Kind() != reflect.Pointer {
return fmt.Errorf("data must be pointer")
}
switch v.Elem().Kind() {
case reflect.Slice:
return i.dealFile(sheetIndex)
default:
return fmt.Errorf("data must be slice")
}
}
func (i *Importer) dealFile(sheetIndex int) error {
sheet := i.Sheets[sheetIndex]
rows, err := i.xlsxFile.Rows(sheet)
if err != nil {
return err
}
vdata := reflect.ValueOf(i.Data).Elem()
if vdata.Type().Elem().Kind() != reflect.Struct {
return fmt.Errorf("element must be struct")
}
testData := reflect.New(vdata.Type().Elem())
tempDic := make(map[int]string)
for i := 0; i < testData.Elem().NumField(); i++ {
t := testData.Elem().Type().Field(i)
tag, ok := t.Tag.Lookup("import")
if ok {
tagMap := dealTag(tag)
index, _ := strconv.Atoi(tagMap["index"])
tempDic[index] = t.Name
}
}
rowIndex := 0
for rows.Next() {
rowIndex += 1
// 第一行为表头
if rowIndex > 1 {
row, err := rows.Columns()
if err != nil {
return err
}
newData := reflect.New(vdata.Type().Elem())
for colIndex := range row {
colIndex += 1
cellName, _ := excelize.CoordinatesToCellName(colIndex, rowIndex)
value, _ := i.xlsxFile.GetCellValue(sheet, cellName)
if fieldName, ok := tempDic[colIndex]; ok {
field := newData.Elem().FieldByName(fieldName)
switch field.Kind() {
case reflect.String:
field.SetString(value)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
intValue, _ := strconv.Atoi(value)
field.SetInt(int64(intValue))
case reflect.Float32, reflect.Float64:
floatValue, _ := strconv.ParseFloat(value, 64)
field.SetFloat(floatValue)
case reflect.Bool:
boolValue, _ := strconv.ParseBool(value)
field.SetBool(boolValue)
// 如果是结构体只支持时间类型并且结构体的字段类型必须是time.Time不能为自定的时间类型并且excel里面的时间格式必须是yyyy-mm-dd或者yyyy-mm-dd hh:mm:ss
case reflect.Struct:
t := time.Time{}
if strings.Contains(value, ":") {
t, _ = time.Parse(time.DateTime, value)
} else {
t, _ = time.Parse(time.DateOnly, value)
}
field.Set(reflect.ValueOf(t))
}
}
}
vdata.Set(reflect.Append(vdata, newData.Elem()))
}
}
if err = rows.Close(); err != nil {
return err
}
return nil
}
func dealTag(tag string) map[string]string {
tag_list := strings.Split(tag, ",")
tag_map := make(map[string]string)
for _, tag := range tag_list {
tag_kv := strings.Split(tag, ":")
if len(tag_kv) != 2 {
continue
}
tag_map[tag_kv[0]] = tag_kv[1]
}
return tag_map
}

BIN
test7.xlsx 100644

Binary file not shown.