# Excel导出工具文档 ## 概述 Excel导出工具提供了将数据导出到Excel文件的功能,支持结构体切片、自定义格式化、多工作表等特性。通过工厂模式,外部项目可以方便地使用Excel导出功能。 ## 功能特性 - **黑盒模式**:提供直接调用的方法,无需获取Excel对象 - **延迟初始化**:Excel导出器在首次使用时才创建 - **支持结构体切片**:自动将结构体切片转换为Excel行数据 - **支持嵌套字段**:支持访问嵌套结构体字段(如 "User.Name") - **自定义格式化**:支持自定义字段值的格式化函数 - **自动列宽**:自动调整列宽以适应内容 - **表头样式**:自动应用表头样式(加粗、背景色等) - **智能工作表管理**:自动处理工作表的创建和删除,避免产生空sheet - **ExportData接口**:支持实现ExportData接口进行高级定制 - **空数据处理**:即使数据为空(nil或空切片),也会正常生成表头 - **统一接口**:只暴露 `ExportToWriter` 一个核心方法 ## 使用方法 ### 1. 创建工厂 ```go import "git.toowon.com/jimmy/go-common/factory" // 从配置文件创建 fac, err := factory.NewFactoryFromFile("./config.json") // 或Excel导出不需要配置,可以传nil fac := factory.NewFactory(nil) ``` ### 2. 导出结构体切片到文件 ```go // 定义结构体 type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` Status int `json:"status"` } // 准备数据 users := []User{ {ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1}, {ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 1}, } // 定义导出列 columns := []factory.ExportColumn{ {Header: "ID", Field: "ID", Width: 10}, {Header: "姓名", Field: "Name", Width: 20}, {Header: "邮箱", Field: "Email", Width: 30}, {Header: "创建时间", Field: "CreatedAt", Width: 20}, {Header: "状态", Field: "Status", Width: 10}, } // 导出到文件 err := fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users) if err != nil { log.Fatal(err) } ``` ### 3. 导出到HTTP响应 ```go import "net/http" func exportUsersHandler(w http.ResponseWriter, r *http.Request) { fac, _ := factory.NewFactoryFromFile("./config.json") users := []User{ {ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1}, {ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 1}, } columns := []factory.ExportColumn{ {Header: "ID", Field: "ID"}, {Header: "姓名", Field: "Name"}, {Header: "邮箱", Field: "Email"}, } // 设置HTTP响应头 w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") w.Header().Set("Content-Disposition", "attachment; filename=users.xlsx") // 导出到响应 err := fac.ExportToExcel(w, "用户列表", columns, users) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } ``` ### 4. 使用格式化函数 ```go import "git.toowon.com/jimmy/go-common/excel" columns := []factory.ExportColumn{ {Header: "ID", Field: "ID", Width: 10}, {Header: "姓名", Field: "Name", Width: 20}, { Header: "创建时间", Field: "CreatedAt", Width: 20, Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数 }, { Header: "状态", Field: "Status", Width: 10, Format: func(value interface{}) string { // 自定义格式化函数 if status, ok := value.(int); ok { if status == 1 { return "启用" } return "禁用" } return "" }, }, } err := fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users) ``` ### 5. 使用ExportData接口(高级功能) ```go // 实现ExportData接口 type UserExportData struct { users []User } // GetExportColumns 获取导出列定义 func (d *UserExportData) GetExportColumns() []excel.ExportColumn { return []excel.ExportColumn{ {Header: "ID", Field: "ID", Width: 10}, {Header: "姓名", Field: "Name", Width: 20}, {Header: "邮箱", Field: "Email", Width: 30}, } } // GetExportRows 获取导出数据行 func (d *UserExportData) GetExportRows() [][]interface{} { rows := make([][]interface{}, 0, len(d.users)) for _, user := range d.users { row := []interface{}{ user.ID, user.Name, user.Email, } rows = append(rows, row) } return rows } // 使用 exportData := &UserExportData{users: users} columns := exportData.GetExportColumns() err := fac.ExportToExcelFile("users.xlsx", "用户列表", columns, exportData) ``` ### 6. 获取Excel对象(高级功能) ```go // 获取Excel导出器对象(仅在需要高级功能时使用) excel, err := fac.GetExcel() if err != nil { log.Fatal(err) } // 获取excelize.File对象,用于高级操作 file := excel.GetFile() // 创建多个工作表 file.NewSheet("Sheet2") file.SetCellValue("Sheet2", "A1", "数据") // 自定义样式 style, _ := file.NewStyle(&excelize.Style{ Font: &excelize.Font{ Bold: true, Size: 14, }, }) file.SetCellStyle("Sheet2", "A1", "A1", style) ``` ## API 参考 ### 工厂方法 #### ExportToExcel(w io.Writer, sheetName string, columns []ExportColumn, data interface{}) error 导出数据到Writer。 **参数:** - `w`: Writer对象(如http.ResponseWriter) - `sheetName`: 工作表名称(可选,默认为"Sheet1") - `columns`: 列定义 - `data`: 数据列表(可以是结构体切片或实现了ExportData接口的对象) **返回:** 错误信息 **数据为空处理:** - 支持 `nil`、空切片、指针类型等空数据情况 - 即使数据为空,表头也会正常生成 **工作表处理逻辑:** - 如果 `sheetName` 为空,默认使用 "Sheet1" - 如果指定的工作表不存在,会自动创建 - 使用自定义名称时会自动删除默认的"Sheet1",避免产生空sheet **示例:** ```go fac.ExportToExcel(w, "用户列表", columns, users) fac.ExportToExcel(w, "空数据", columns, []User{}) // 空数据也会生成表头 ``` #### ExportToExcelFile(filePath string, sheetName string, columns []ExportColumn, data interface{}) error 导出数据到文件。 **参数:** - `filePath`: 文件路径 - `sheetName`: 工作表名称(可选,默认为"Sheet1") - `columns`: 列定义 - `data`: 数据列表(可以是结构体切片或实现了ExportData接口的对象) **返回:** 错误信息 **实现说明:** - 此方法内部创建文件并调用 `ExportToWriter` - 文件相关的封装由工厂方法处理 **工作表处理逻辑:** - 如果 `sheetName` 为空,默认使用 "Sheet1" - 如果指定的工作表不存在,会自动创建 - 使用自定义名称时会自动删除默认的"Sheet1",避免产生空sheet **示例:** ```go fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users) fac.ExportToExcelFile("empty.xlsx", "空数据", columns, []User{}) // 空数据也会生成表头 ``` ### 高级方法 #### GetExcel() (*excel.Excel, error) 获取Excel导出器对象。 **返回:** Excel导出器对象和错误信息 **说明:** 仅在需要使用高级功能时使用,推荐使用黑盒方法 ### 结构体类型 #### ExportColumn 导出列定义。 ```go type ExportColumn struct { Header string // 表头名称 Field string // 数据字段名(支持嵌套字段,如 "User.Name") Width float64 // 列宽(可选,0表示自动) Format func(interface{}) string // 格式化函数(可选) } ``` **字段说明:** - `Header`: 表头显示的名称 - `Field`: 数据字段名,支持嵌套字段(如 "User.Name") - `Width`: 列宽,0表示自动调整 - `Format`: 格式化函数,用于自定义字段值的显示格式 ### 格式化函数适配器 #### excel.AdaptTimeFormatter(fn func(time.Time, ...string) string) func(interface{}) string 适配器函数:将tools包的格式化函数转换为Excel Format字段需要的函数类型。 **参数:** - `fn`: tools包的格式化函数(如 `tools.FormatDate`、`tools.FormatDateTime` 等) **返回:** Excel Format字段需要的格式化函数 **说明:** - 允许直接使用tools包的任何格式化函数 **示例:** ```go import ( "git.toowon.com/jimmy/go-common/excel" "git.toowon.com/jimmy/go-common/tools" ) // 使用tools.FormatDate Format: excel.AdaptTimeFormatter(tools.FormatDate) // 使用tools.FormatDateTime Format: excel.AdaptTimeFormatter(tools.FormatDateTime) // 使用tools.FormatTime Format: excel.AdaptTimeFormatter(tools.FormatTime) // 使用自定义格式化函数 Format: excel.AdaptTimeFormatter(func(t time.Time) string { return tools.Format(t, "2006-01-02 15:04:05", "Asia/Shanghai") }) ``` ### ExportData接口 实现此接口的结构体可以直接导出。 ```go type ExportData interface { // GetExportColumns 获取导出列定义 GetExportColumns() []ExportColumn // GetExportRows 获取导出数据行 GetExportRows() [][]interface{} } ``` ## 完整示例 ```go package main import ( "net/http" "time" "git.toowon.com/jimmy/go-common/excel" "git.toowon.com/jimmy/go-common/factory" ) type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` Status int `json:"status"` } func exportUsersHandler(w http.ResponseWriter, r *http.Request) { fac, _ := factory.NewFactoryFromFile("./config.json") // 从数据库或其他数据源获取数据 users := []User{ {ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1}, {ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 1}, } // 定义导出列 columns := []factory.ExportColumn{ {Header: "ID", Field: "ID", Width: 10}, {Header: "姓名", Field: "Name", Width: 20}, {Header: "邮箱", Field: "Email", Width: 30}, { Header: "创建时间", Field: "CreatedAt", Width: 20, Format: excel.AdaptTimeFormatter(tools.FormatDateTime), }, { Header: "状态", Field: "Status", Width: 10, Format: func(value interface{}) string { if status, ok := value.(int); ok { if status == 1 { return "启用" } return "禁用" } return "" }, }, } // 设置HTTP响应头 w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") w.Header().Set("Content-Disposition", "attachment; filename=users.xlsx") // 导出到响应 err := fac.ExportToExcel(w, "用户列表", columns, users) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } func main() { http.HandleFunc("/export/users", exportUsersHandler) http.ListenAndServe(":8080", nil) } ``` ## 设计优势 1. **降低复杂度**:调用方无需关心Excel文件对象的创建和管理 2. **延迟初始化**:Excel导出器在首次使用时才创建 3. **统一接口**:所有操作通过工厂方法调用 4. **灵活扩展**:支持结构体切片、自定义格式化、ExportData接口等多种方式 5. **自动优化**:自动调整列宽、应用表头样式等 ## 注意事项 1. **配置**:Excel导出不需要配置,可以传nil创建工厂 2. **错误处理**:所有方法都可能返回错误,需要正确处理 3. **延迟初始化**:Excel导出器在首次使用时才创建,首次调用可能稍慢 4. **字段名匹配**:Field字段名必须与结构体字段名匹配(区分大小写) 5. **嵌套字段**:支持嵌套字段访问(如 "User.Name"),但需要确保字段路径正确 6. **格式化函数**:格式化函数返回的字符串会直接写入Excel单元格 7. **列宽设置**:Width为0时会自动调整列宽,但可能影响性能(大数据量时建议设置固定宽度) 8. **工作表处理**:工具会自动处理工作表的创建和删除,确保不会产生空sheet 9. **空数据处理**:即使数据为 `nil` 或空切片,表头也会正常生成 10. **方法设计**: - `excel` 包只暴露 `ExportToWriter` 一个核心方法 - 文件相关的封装由工厂方法 `ExportToExcelFile` 处理 ## 最佳实践 1. **使用工厂方法**:推荐使用 `ExportToExcel()` 和 `ExportToExcelFile()` 2. **设置列宽**:对于大数据量,建议设置固定列宽以提高性能 3. **使用格式化函数**:对于日期时间、状态等字段,使用格式化函数提高可读性 4. **错误处理**:始终检查导出方法的返回值 5. **HTTP响应**:导出到HTTP响应时,记得设置正确的Content-Type和Content-Disposition头 6. **工作表命名**:推荐使用有意义的工作表名称,工具会自动处理工作表的创建和删除 7. **空数据场景**:即使查询结果为空,也可以导出包含表头的Excel文件 ## 示例 完整示例请参考 `examples/excel_example.go`