首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

ASP.NET 從 SQL 資料庫匯出 Word 文件:方案選型與核心代碼

     編輯:程式設計綜合問答

方案對比

方案優點缺點適用場景
Open XML SDK (Microsoft 官方)無需安裝 Office、效能高、支援 .docx 所有功能、免費開源API 底層較繁瑣、需手動組裝 XML 結構、學習曲線陡伺服器端批量生成、高併發、不想付費
Aspose.Words (商業庫)API 極簡單 (類 Word 物件模型)、支援郵件合併、轉 PDF 完美、相容性極強**收費授權較貴**、DLL 體積大企業級專案、複雜報表、預算充足、求開發效率
COM Interop (Word Automation)程式碼直觀 (VBA 風格)、功能最全**嚴禁用於伺服器端** (Microsoft 官方不支援)、需安裝 Office、併發極差、易卡死僅限桌面端單機工具
NPOI (開源)免費、支援 .doc/.xls (舊格式).docx (OOXML) 支援較弱、Word 功能不如 Open XML SDK 完整維護舊系統 .doc 格式、簡單表格導出

推薦方案:Open XML SDK (免費、無 Office 依賴、生產級)

1. NuGet 安裝

Install-Package DocumentFormat.OpenXml

2. 核心代碼架構 (針對題目需求:標題居中、多級列表、表格、圖片)

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Data;
using System.IO;

public byte[] GenerateWordReport(DataTable dtMain, List dtTables, List images) {
    using (MemoryStream ms = new MemoryStream()) {
        using (WordprocessingDocument doc = WordprocessingDocument.Create(ms, WordprocessingDocumentType.Document)) {
            MainDocumentPart mainPart = doc.AddMainDocumentPart();
            mainPart.Document = new Document();
            Body body = mainPart.Document.AppendChild(new Body());

            // --- 樣式預定義 ---
            // 標題樣式:置中、字體、大小
            ParagraphProperties titleProps = new ParagraphProperties(
                new Justification() { Val = JustificationValues.Center },
                new SpacingBetweenLines() { After = "200" }
            );
            RunProperties titleRunProps = new RunProperties(
                new RunFonts() { Ascii = "微軟雅黑", HighAnsi = "微軟雅黑" },
                new FontSize() { Val = "32" }, // 16pt = 32 half-points
                new Bold()
            );

            // 1. 主標題
            AppendParagraph(body, "數據分析報告", titleProps, titleRunProps);

            // 2. 多級列表 (一、 1、 (1) 結構)
            // Open XML 需定義 NumberingDefinitionsPart,此處簡化為手動添加編號文字
            AppendNumberedItem(body, "一、內容1", 1, "微軟雅黑", "24");
            AppendNumberedItem(body, "1、*******", 2, "微軟雅黑", "22");
            AppendNumberedItem(body, "2、*****", 2, "微軟雅黑", "22");
            AppendNumberedItem(body, "二、內容二", 1, "微軟雅黑", "24");
            AppendNumberedItem(body, "(1)*****", 3, "微軟雅黑", "22");

            // 3. 動態表格 (來自 DataTable)
            if (dtTables != null && dtTables.Count > 0) {
                AppendParagraph(body, "三、數據表格", titleProps, titleRunProps); // 子標題
                foreach (var table in dtTables) {
                    AppendDataTable(body, table);
                }
            }

            // 4. 圖片插入
            if (images != null) {
                foreach (var imgBytes in images) {
                    AppendImage(body, mainPart, imgBytes);
                }
            }

            mainPart.Document.Save();
        }
        return ms.ToArray();
    }
}

// 輔助方法:追加段落
void AppendParagraph(Body body, string text, ParagraphProperties pPr, RunProperties rPr) {
    Paragraph p = body.AppendChild(new Paragraph(pPr));
    Run r = p.AppendChild(new Run(rPr));
    r.AppendChild(new Text(text) { Space = SpaceProcessingModeValues.Preserve });
}

// 輔助方法:追加表格 (核心邏輯)
void AppendDataTable(Body body, DataTable dt) {
    Table table = new Table();
    // 表格屬性:邊框、置中、自動調整
    table.AppendChild(new TableProperties(
        new TableBorders(
            new TopBorder() { Val = BorderValues.Single, Size = 4 },
            new BottomBorder() { Val = BorderValues.Single, Size = 4 },
            new LeftBorder() { Val = BorderValues.Single, Size = 4 },
            new RightBorder() { Val = BorderValues.Single, Size = 4 },
            new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
            new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
        ),
        new TableJustification() { Val = TableRowAlignmentValues.Center },
        new TableLayout() { Type = TableLayoutValues.Fixed }
    ));

    // 表頭
    TableRow headerRow = new TableRow();
    foreach (DataColumn col in dt.Columns) {
        TableCell cell = new TableCell(new Paragraph(new Run(new Text(col.ColumnName))));
        // 可加粗表頭
        headerRow.Append(cell);
    }
    table.Append(headerRow);

    // 數據行
    foreach (DataRow row in dt.Rows) {
        TableRow dataRow = new TableRow();
        foreach (var item in row.ItemArray) {
            dataRow.Append(new TableCell(new Paragraph(new Run(new Text(item.ToString())))));
        }
        table.Append(dataRow);
    }
    body.Append(table);
}

// 輔助方法:插入圖片
void AppendImage(Body body, MainDocumentPart mainPart, byte[] imgBytes) {
    ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg); // 或 Png
    using (MemoryStream imgStream = new MemoryStream(imgBytes)) {
        imagePart.FeedData(imgStream);
    }
    string relId = mainPart.GetIdOfPart(imagePart);
    
    var element = new Drawing(
        new DW.Inline(
            new DW.Extent() { Cx = 990000L, Cy = 792000L }, // 大小 EMU
            new DW.EffectExtent() { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
            new DW.DocProperties() { Id = (UInt32Value)1U, Name = "Picture" },
            new DW.NonVisualGraphicFrameDrawingProperties(
                new A.GraphicFrameLocks() { NoChangeAspect = true }),
            new A.Graphic(
                new A.GraphicData(
                    new PIC.Picture(
                        new PIC.NonVisualPictureProperties(
                            new PIC.NonVisualDrawingProperties() { Id = 0U, Name = "Image" },
                            new PIC.NonVisualPictureDrawingProperties()),
                        new PIC.BlipFill(
                            new A.Blip() { Embed = relId, CompressionState = A.BlipCompressionValues.Print },
                            new A.Stretch(new A.FillRectangle())),
                        new PIC.ShapeProperties(
                            new A.Transform2D(
                                new A.Offset() { X = 0L, Y = 0L },
                                new A.Extents() { Cx = 990000L, Cy = 792000L }),
                            new A.PresetGeometry(new A.AdjustValueList()) { Preset = A.ShapeTypeValues.Rectangle }))
                ) { Uri = "https://schemas.openxmlformats.org/drawingml/2006/picture" })
        ) { DistanceFromTop = 0, DistanceFromBottom = 0, DistanceFromLeft = 0, DistanceFromRight = 0 });
    
    Paragraph p = body.AppendChild(new Paragraph(new ParagraphProperties(new Justification() { Val = JustificationValues.Center })));
    Run r = p.AppendChild(new Run());
    r.Append(element);
}

3. 前端下載觸發

public void DownloadWord() {
    byte[] fileBytes = GenerateWordReport(...); // 獲取數據
    Response.Clear();
    Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    Response.AddHeader("Content-Disposition", "attachment;filename=Report_" + DateTime.Now.ToString("yyyyMMdd") + ".docx");
    Response.BinaryWrite(fileBytes);
    Response.End();
}

總結

**不建議使用 COM 元件 (Word Automation) 在 ASP.NET 中**,極易導致 IIS 僵死、記憶體洩漏、權限問題。
**首選 Open XML SDK**:免費、輕量、官方標準、適合伺服器端高併發。
**預算允許且追求極致開發速度/複雜排版**:Aspose.Words 是最佳商業選擇。
上述代碼展示了 Open XML SDK 處理「標題居中、多級列表、動態表格、圖片」的核心邏輯,可直接擴展應用於實際專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved