11 示例项目 - ZeroHawkeye/wordZero GitHub Wiki
WordZero 示例项目
本文档提供 WordZero 库的完整示例项目,展示实际应用场景和最佳实践。
📋 目录
基础示例
1. 简单文档生成器
创建一个简单的文档生成器,展示基本功能的使用。
package main
import (
"fmt"
"log"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
func main() {
// 创建新文档
doc := document.New()
// 添加标题
title := doc.AddParagraph("我的第一个Word文档")
title.SetStyle(style.StyleTitle)
// 添加副标题
subtitle := doc.AddParagraph("使用WordZero创建")
subtitle.SetStyle(style.StyleSubtitle)
// 添加正文
content := doc.AddParagraph("这是一个使用WordZero库创建的简单文档示例。")
content.SetStyle(style.StyleNormal)
// 保存文档
err := doc.Save("my_first_document.docx")
if err != nil {
log.Fatal(err)
}
fmt.Println("文档创建成功!")
}
2. 格式化文本示例
展示各种文本格式化选项。
package main
import (
"github.com/ZeroHawkeye/wordZero/pkg/document"
)
func main() {
doc := document.New()
// 创建不同格式的文本
formats := []*document.TextFormat{
{FontName: "Arial", FontSize: 12, Bold: true},
{FontName: "Times New Roman", FontSize: 14, Italic: true},
{FontName: "Courier New", FontSize: 10, FontColor: "FF0000"},
{FontName: "Calibri", FontSize: 16, Bold: true, Italic: true},
}
texts := []string{
"这是粗体文本",
"这是斜体文本",
"这是红色文本",
"这是粗体斜体文本",
}
for i, text := range texts {
para := doc.AddFormattedParagraph(text, formats[i])
para.SetAlignment(document.AlignCenter)
}
doc.Save("formatted_text_example.docx")
}
实际应用场景
1. 报告生成器
创建一个完整的报告生成器,包含目录、表格、图表等。
package main
import (
"fmt"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
type ReportData struct {
Title string
Author string
Date time.Time
Summary string
Sections []Section
TableData [][]string
}
type Section struct {
Title string
Content string
Level int
}
func GenerateReport(data ReportData) error {
doc := document.New()
// 设置文档属性
doc.SetTitle(data.Title)
doc.SetAuthor(data.Author)
// 添加封面
addCoverPage(doc, data)
// 生成目录
generateTOC(doc)
// 添加摘要
addSummary(doc, data.Summary)
// 添加各个章节
for _, section := range data.Sections {
addSection(doc, section)
}
// 添加数据表格
addDataTable(doc, data.TableData)
// 添加页眉页脚
addHeaderFooter(doc, data.Title)
// 保存文档
filename := fmt.Sprintf("report_%s.docx",
time.Now().Format("20060102_150405"))
return doc.Save(filename)
}
func addCoverPage(doc *document.Document, data ReportData) {
// 标题
title := doc.AddParagraph(data.Title)
title.SetStyle(style.StyleTitle)
title.SetAlignment(document.AlignCenter)
// 作者和日期
author := doc.AddParagraph(fmt.Sprintf("作者:%s", data.Author))
author.SetAlignment(document.AlignCenter)
date := doc.AddParagraph(fmt.Sprintf("日期:%s",
data.Date.Format("2006年01月02日")))
date.SetAlignment(document.AlignCenter)
}
func generateTOC(doc *document.Document) {
config := &document.TOCConfig{
Title: "目录",
MaxLevel: 3,
ShowPageNum: true,
}
doc.GenerateTOC(config)
}
func addSummary(doc *document.Document, summary string) {
heading := doc.AddParagraph("摘要")
heading.SetStyle(style.StyleHeading1)
content := doc.AddParagraph(summary)
content.SetStyle(style.StyleNormal)
}
func addSection(doc *document.Document, section Section) {
var styleID string
switch section.Level {
case 1:
styleID = style.StyleHeading1
case 2:
styleID = style.StyleHeading2
case 3:
styleID = style.StyleHeading3
default:
styleID = style.StyleHeading1
}
heading := doc.AddParagraph(section.Title)
heading.SetStyle(styleID)
content := doc.AddParagraph(section.Content)
content.SetStyle(style.StyleNormal)
}
func addDataTable(doc *document.Document, data [][]string) {
if len(data) == 0 {
return
}
heading := doc.AddParagraph("数据表格")
heading.SetStyle(style.StyleHeading1)
config := &document.TableConfig{
Rows: len(data),
Cols: len(data[0]),
Width: 8000, // 设置表格宽度为8000磅(约11英寸)
Data: data,
}
table := doc.AddTable(config)
if table != nil {
// 应用表格样式
styleConfig := &document.TableStyleConfig{
Template: document.TableStyleTemplateGrid,
FirstRowHeader: true,
}
table.ApplyTableStyle(styleConfig)
}
}
func addHeaderFooter(doc *document.Document, title string) {
// 添加页眉
err := doc.AddHeaderWithPageNumber(document.HeaderFooterTypeDefault, title, true)
if err != nil {
log.Printf("添加页眉失败: %v", err)
}
// 添加页脚
err = doc.AddFooterWithPageNumber(document.HeaderFooterTypeDefault, "机密文档", true)
if err != nil {
log.Printf("添加页脚失败: %v", err)
}
}
func main() {
data := ReportData{
Title: "2024年度业务报告",
Author: "张三",
Date: time.Now(),
Summary: "本报告总结了2024年度的业务发展情况...",
Sections: []Section{
{Title: "业务概况", Content: "业务发展良好...", Level: 1},
{Title: "财务状况", Content: "财务状况稳定...", Level: 1},
{Title: "市场分析", Content: "市场前景乐观...", Level: 2},
},
TableData: [][]string{
{"月份", "收入", "支出", "利润"},
{"1月", "100万", "80万", "20万"},
{"2月", "120万", "90万", "30万"},
{"3月", "110万", "85万", "25万"},
},
}
err := GenerateReport(data)
if err != nil {
fmt.Printf("生成报告失败: %v\n", err)
} else {
fmt.Println("报告生成成功!")
}
}
2. 合同生成器
创建一个合同文档生成器。
package main
import (
"fmt"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
type ContractData struct {
ContractNumber string
PartyA Party
PartyB Party
Subject string
Amount float64
StartDate time.Time
EndDate time.Time
Terms []string
SignDate time.Time
}
type Party struct {
Name string
Address string
Contact string
Phone string
}
func GenerateContract(data ContractData) error {
doc := document.New()
// 设置页面
doc.SetPageMargins(2.5, 2.0, 2.5, 2.0) // 厘米
// 合同标题
title := doc.AddParagraph("服务合同")
title.SetStyle(style.StyleTitle)
title.SetAlignment(document.AlignCenter)
// 合同编号
contractNum := doc.AddParagraph(fmt.Sprintf("合同编号:%s",
data.ContractNumber))
contractNum.SetAlignment(document.AlignCenter)
// 甲乙双方信息
addPartyInfo(doc, "甲方", data.PartyA)
addPartyInfo(doc, "乙方", data.PartyB)
// 合同正文
addContractBody(doc, data)
// 合同条款
addContractTerms(doc, data.Terms)
// 签署信息
addSignatureSection(doc, data)
filename := fmt.Sprintf("contract_%s.docx", data.ContractNumber)
return doc.Save(filename)
}
func addPartyInfo(doc *document.Document, partyType string, party Party) {
info := fmt.Sprintf(`%s:
名称:%s
地址:%s
联系人:%s
电话:%s`, partyType, party.Name, party.Address, party.Contact, party.Phone)
para := doc.AddParagraph(info)
para.SetStyle(style.StyleNormal)
}
func addContractBody(doc *document.Document, data ContractData) {
heading := doc.AddParagraph("合同内容")
heading.SetStyle(style.StyleHeading1)
content := fmt.Sprintf(`根据《中华人民共和国合同法》及相关法律法规,甲乙双方在平等、自愿的基础上,就%s事宜达成如下协议:
合同金额:%.2f元
合同期限:%s 至 %s`,
data.Subject,
data.Amount,
data.StartDate.Format("2006年01月02日"),
data.EndDate.Format("2006年01月02日"))
para := doc.AddParagraph(content)
para.SetStyle(style.StyleNormal)
}
func addContractTerms(doc *document.Document, terms []string) {
heading := doc.AddParagraph("合同条款")
heading.SetStyle(style.StyleHeading1)
for i, term := range terms {
termText := fmt.Sprintf("%d. %s", i+1, term)
para := doc.AddParagraph(termText)
para.SetStyle(style.StyleNormal)
para.SetIndentation(0.5, 0, 0) // 首行缩进
}
}
func addSignatureSection(doc *document.Document, data ContractData) {
heading := doc.AddParagraph("签署")
heading.SetStyle(style.StyleHeading1)
signText := fmt.Sprintf(`甲方签字:________________ 日期:%s
乙方签字:________________ 日期:%s
本合同一式两份,甲乙双方各执一份,具有同等法律效力。`,
data.SignDate.Format("2006年01月02日"),
data.SignDate.Format("2006年01月02日"))
para := doc.AddParagraph(signText)
para.SetStyle(style.StyleNormal)
}
func main() {
data := ContractData{
ContractNumber: "HT2024001",
PartyA: Party{
Name: "ABC科技有限公司",
Address: "北京市朝阳区xxx路xxx号",
Contact: "李经理",
Phone: "010-12345678",
},
PartyB: Party{
Name: "XYZ软件开发公司",
Address: "上海市浦东新区xxx路xxx号",
Contact: "王工程师",
Phone: "021-87654321",
},
Subject: "软件开发服务",
Amount: 500000.00,
StartDate: time.Now(),
EndDate: time.Now().AddDate(0, 6, 0),
Terms: []string{
"甲方负责提供详细的需求文档",
"乙方负责按时交付高质量的软件产品",
"项目分三个阶段进行,每个阶段完成后进行验收",
"如有争议,双方应友好协商解决",
},
SignDate: time.Now(),
}
err := GenerateContract(data)
if err != nil {
fmt.Printf("生成合同失败: %v\n", err)
} else {
fmt.Println("合同生成成功!")
}
}
完整项目模板
文档生成服务
创建一个完整的文档生成微服务。
// main.go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
type DocumentService struct {
// 移除模板系统,直接处理不同类型的请求
}
type DocumentRequest struct {
Type string `json:"type"` // 文档类型:report, contract, invoice
Data map[string]interface{} `json:"data"` // 文档数据
}
func NewDocumentService() *DocumentService {
return &DocumentService{}
}
func (ds *DocumentService) GenerateDocument(w http.ResponseWriter, r *http.Request) {
var req DocumentRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
var doc *document.Document
var err error
// 根据类型生成不同的文档
switch req.Type {
case "report":
doc, err = ds.generateReport(req.Data)
case "contract":
doc, err = ds.generateContract(req.Data)
case "invoice":
doc, err = ds.generateInvoice(req.Data)
default:
http.Error(w, "Unknown document type", http.StatusBadRequest)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("Generation error: %v", err),
http.StatusInternalServerError)
return
}
// 保存到临时文件
filename := fmt.Sprintf("temp_%d.docx", time.Now().Unix())
if err := doc.Save(filename); err != nil {
http.Error(w, "Failed to save document",
http.StatusInternalServerError)
return
}
// 返回文件
w.Header().Set("Content-Type",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document")
w.Header().Set("Content-Disposition",
fmt.Sprintf("attachment; filename=%s", filename))
http.ServeFile(w, r, filename)
}
func (ds *DocumentService) generateReport(data map[string]interface{}) (*document.Document, error) {
doc := document.New()
// 基本报告生成逻辑
title, ok := data["title"].(string)
if !ok {
title = "默认报告"
}
titlePara := doc.AddParagraph(title)
titlePara.SetStyle(style.StyleTitle)
titlePara.SetAlignment(document.AlignCenter)
content, ok := data["content"].(string)
if !ok {
content = "报告内容..."
}
contentPara := doc.AddParagraph(content)
contentPara.SetStyle(style.StyleNormal)
return doc, nil
}
func (ds *DocumentService) generateContract(data map[string]interface{}) (*document.Document, error) {
doc := document.New()
// 基本合同生成逻辑
title := doc.AddParagraph("服务合同")
title.SetStyle(style.StyleTitle)
title.SetAlignment(document.AlignCenter)
// 添加合同编号
contractNum, ok := data["contractNumber"].(string)
if !ok {
contractNum = "HT2024XXX"
}
numPara := doc.AddParagraph(fmt.Sprintf("合同编号:%s", contractNum))
numPara.SetAlignment(document.AlignCenter)
return doc, nil
}
func (ds *DocumentService) generateInvoice(data map[string]interface{}) (*document.Document, error) {
doc := document.New()
// 基本发票生成逻辑
title := doc.AddParagraph("发票")
title.SetStyle(style.StyleTitle)
title.SetAlignment(document.AlignCenter)
// 添加发票信息
invoiceNum, ok := data["invoiceNumber"].(string)
if !ok {
invoiceNum = "INV2024XXX"
}
numPara := doc.AddParagraph(fmt.Sprintf("发票编号:%s", invoiceNum))
numPara.SetAlignment(document.AlignCenter)
return doc, nil
}
func main() {
service := NewDocumentService()
http.HandleFunc("/generate", service.GenerateDocument)
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
fmt.Println("文档生成服务启动在端口 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
性能优化示例
批量文档生成
package main
import (
"fmt"
"sync"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
type BatchProcessor struct {
workerCount int
jobs chan DocumentJob
results chan DocumentResult
wg sync.WaitGroup
}
type DocumentJob struct {
ID int
Data interface{}
}
type DocumentResult struct {
ID int
Filename string
Error error
Duration time.Duration
}
func NewBatchProcessor(workerCount int) *BatchProcessor {
return &BatchProcessor{
workerCount: workerCount,
jobs: make(chan DocumentJob, 100),
results: make(chan DocumentResult, 100),
}
}
func (bp *BatchProcessor) Start() {
for i := 0; i < bp.workerCount; i++ {
bp.wg.Add(1)
go bp.worker()
}
}
func (bp *BatchProcessor) worker() {
defer bp.wg.Done()
for job := range bp.jobs {
start := time.Now()
filename, err := bp.processDocument(job)
duration := time.Since(start)
bp.results <- DocumentResult{
ID: job.ID,
Filename: filename,
Error: err,
Duration: duration,
}
}
}
func (bp *BatchProcessor) processDocument(job DocumentJob) (string, error) {
doc := document.New()
// 快速文档生成逻辑
title := doc.AddParagraph(fmt.Sprintf("文档 #%d", job.ID))
title.SetStyle(style.StyleTitle)
content := doc.AddParagraph("这是批量生成的文档内容。")
content.SetStyle(style.StyleNormal)
filename := fmt.Sprintf("batch_doc_%d.docx", job.ID)
err := doc.Save(filename)
return filename, err
}
func (bp *BatchProcessor) AddJob(job DocumentJob) {
bp.jobs <- job
}
func (bp *BatchProcessor) Close() {
close(bp.jobs)
bp.wg.Wait()
close(bp.results)
}
func (bp *BatchProcessor) GetResults() <-chan DocumentResult {
return bp.results
}
func main() {
processor := NewBatchProcessor(4) // 4个工作协程
processor.Start()
// 添加100个任务
go func() {
for i := 1; i <= 100; i++ {
processor.AddJob(DocumentJob{
ID: i,
Data: fmt.Sprintf("Data for document %d", i),
})
}
processor.Close()
}()
// 收集结果
var totalDuration time.Duration
successCount := 0
for result := range processor.GetResults() {
if result.Error != nil {
fmt.Printf("文档 %d 生成失败: %v\n", result.ID, result.Error)
} else {
fmt.Printf("文档 %d 生成成功: %s (耗时: %v)\n",
result.ID, result.Filename, result.Duration)
successCount++
}
totalDuration += result.Duration
}
fmt.Printf("\n批量处理完成:\n")
fmt.Printf("成功: %d\n", successCount)
fmt.Printf("总耗时: %v\n", totalDuration)
fmt.Printf("平均耗时: %v\n", totalDuration/time.Duration(successCount))
}
错误处理示例
健壮的文档处理
package main
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
)
type DocumentProcessor struct {
logger *log.Logger
}
func NewDocumentProcessor() *DocumentProcessor {
return &DocumentProcessor{
logger: log.New(os.Stdout, "[DocProcessor] ", log.LstdFlags),
}
}
func (dp *DocumentProcessor) ProcessWithRetry(data interface{}, maxRetries int) error {
var lastErr error
for attempt := 1; attempt <= maxRetries; attempt++ {
err := dp.process(data)
if err == nil {
dp.logger.Printf("处理成功,尝试次数: %d", attempt)
return nil
}
lastErr = err
dp.logger.Printf("尝试 %d/%d 失败: %v", attempt, maxRetries, err)
if attempt < maxRetries {
// 指数退避
time.Sleep(time.Duration(attempt) * time.Second)
}
}
return fmt.Errorf("处理失败,已重试 %d 次: %w", maxRetries, lastErr)
}
func (dp *DocumentProcessor) process(data interface{}) error {
// 验证输入
if err := dp.validateInput(data); err != nil {
return fmt.Errorf("输入验证失败: %w", err)
}
// 创建文档
doc, err := dp.createDocument(data)
if err != nil {
return fmt.Errorf("创建文档失败: %w", err)
}
// 保存文档
if err := dp.saveDocument(doc, "output.docx"); err != nil {
return fmt.Errorf("保存文档失败: %w", err)
}
return nil
}
func (dp *DocumentProcessor) validateInput(data interface{}) error {
if data == nil {
return errors.New("数据不能为空")
}
// 更多验证逻辑...
return nil
}
func (dp *DocumentProcessor) createDocument(data interface{}) (*document.Document, error) {
defer func() {
if r := recover(); r != nil {
dp.logger.Printf("创建文档时发生panic: %v", r)
}
}()
doc := document.New()
// 添加内容的逻辑...
para := doc.AddParagraph("测试内容")
if para == nil {
return nil, errors.New("添加段落失败")
}
return doc, nil
}
func (dp *DocumentProcessor) saveDocument(doc *document.Document, filename string) error {
// 确保目录存在
dir := filepath.Dir(filename)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("创建目录失败: %w", err)
}
// 检查磁盘空间
if err := dp.checkDiskSpace(filename); err != nil {
return fmt.Errorf("磁盘空间检查失败: %w", err)
}
// 保存文档
if err := doc.Save(filename); err != nil {
return fmt.Errorf("保存失败: %w", err)
}
// 验证文件是否正确保存
if err := dp.validateSavedFile(filename); err != nil {
return fmt.Errorf("文件验证失败: %w", err)
}
return nil
}
func (dp *DocumentProcessor) checkDiskSpace(filename string) error {
// 简单的磁盘空间检查
info, err := os.Stat(filepath.Dir(filename))
if err != nil {
return err
}
// 这里可以添加更详细的磁盘空间检查逻辑
_ = info
return nil
}
func (dp *DocumentProcessor) validateSavedFile(filename string) error {
info, err := os.Stat(filename)
if err != nil {
return fmt.Errorf("文件不存在: %w", err)
}
if info.Size() == 0 {
return errors.New("文件大小为0")
}
return nil
}
func main() {
processor := NewDocumentProcessor()
data := map[string]interface{}{
"title": "测试文档",
"content": "这是测试内容",
}
if err := processor.ProcessWithRetry(data, 3); err != nil {
log.Fatalf("文档处理失败: %v", err)
}
fmt.Println("文档处理成功!")
}
这些示例展示了 WordZero 在各种实际场景中的应用,从简单的文档生成到复杂的企业级应用。每个示例都包含了完整的代码和最佳实践建议。
更多示例代码可以在 examples 目录 中找到。