Files
go-common/docs/excel.md

427 lines
12 KiB
Markdown
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.

# Excel导出工具文档
## 概述
Excel导出工具提供了将数据导出到Excel文件的功能支持结构体切片、自定义格式化、多工作表等特性。通过工厂模式外部项目可以方便地使用Excel导出功能。
## 功能特性
- **黑盒模式**提供直接调用的方法无需获取Excel对象
- **延迟初始化**Excel导出器在首次使用时才创建
- **支持结构体切片**自动将结构体切片转换为Excel行数据
- **支持嵌套字段**:支持访问嵌套结构体字段(如 "User.Name"
- **自定义格式化**:支持自定义字段值的格式化函数
- **自动列宽**:自动调整列宽以适应内容
- **表头样式**:自动应用表头样式(加粗、背景色等)
- **ExportData接口**支持实现ExportData接口进行高级定制
## 使用方法
### 1. 创建工厂(推荐)
```go
import "git.toowon.com/jimmy/go-common/factory"
// 方式1从配置文件创建推荐
fac, err := factory.NewFactoryFromFile("./config.json")
if err != nil {
log.Fatal(err)
}
// 方式2从配置对象创建
cfg, _ := config.LoadFromFile("./config.json")
fac := factory.NewFactory(cfg)
// 方式3Excel导出不需要配置可以传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.FormatDateTimeDefault, // 使用便捷的格式化函数
},
{
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接口的对象
**返回:** 错误信息
**示例:**
```go
fac.ExportToExcel(w, "用户列表", columns, users)
```
#### ExportToExcelFile(filePath string, sheetName string, columns []ExportColumn, data interface{}) error
导出数据到文件。
**参数:**
- `filePath`: 文件路径
- `sheetName`: 工作表名称(可选,默认为"Sheet1"
- `columns`: 列定义
- `data`: 数据列表
**返回:** 错误信息
**示例:**
```go
fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users)
```
### 高级方法
#### GetExcel() (*excel.Excel, error)
获取Excel导出器对象。
**返回:** Excel导出器对象和错误信息
**说明:**
- 仅在需要使用高级功能时使用
- 推荐使用黑盒方法:`ExportToExcel()``ExportToExcelFile()`
### 结构体类型
#### 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.FormatDateTime(layout string) func(interface{}) string
创建日期时间格式化函数。
**参数:**
- `layout`: 时间格式,如 "2006-01-02 15:04:05"
**返回:** 格式化函数
**示例:**
```go
Format: excel.FormatDateTime("2006-01-02 15:04:05")
```
#### excel.FormatDate(value interface{}) string
格式化日期格式2006-01-02
**示例:**
```go
Format: excel.FormatDate
```
#### excel.FormatDateTimeDefault(value interface{}) string
格式化日期时间格式2006-01-02 15:04:05
**示例:**
```go
Format: excel.FormatDateTimeDefault
```
### 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.FormatDateTimeDefault,
},
{
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时会自动调整列宽但可能影响性能大数据量时建议设置固定宽度
## 最佳实践
1. **使用黑盒方法**:推荐使用 `ExportToExcel()``ExportToExcelFile()`无需获取Excel对象
2. **设置列宽**:对于大数据量,建议设置固定列宽以提高性能
3. **使用格式化函数**:对于日期时间、状态等字段,使用格式化函数提高可读性
4. **错误处理**:始终检查导出方法的返回值
5. **HTTP响应**导出到HTTP响应时记得设置正确的Content-Type和Content-Disposition头
## 示例
完整示例请参考 `examples/excel_example.go`