.NET Core使用NPOI導出複雜Word詳解

前言:

  最近使用NPOI作了個導出Word文檔的功能,關於使用.NET Core 導出Word文檔的方式有不少。最終我爲何選擇了NPOI來實現了這個功能,首先是NPOI是一個開源,免費且容易上手的第三方框架(而且如今已支持.NET Core,GitHub源碼地址:https://github.com/tonyqus/npoi)。由於以前使用NPOI導出Execl比較多,此次第一次使用NPOI 來導出Word文檔還真沒有什麼頭緒。首先看了下GItHub中的源碼有一個簡單Word導出的示例,而後在看了網上有不少關於NPOI導出Word文檔的案例,發現一個特色網上的好像都差很少,對於我而言網上的這些案例徹底可以實現個人這個功能,可是感受看了網上這些案例對NPOI實例化段落,表格和設置相關樣式不太清楚(多是由於本身笨),而且假如使用網上的方法來實現個人功能的話代碼量會比較大,並且感受代碼很是的冗餘(我是一個追求代碼簡潔的人,怎麼可以容忍這樣的事情發生呢!),所以經過查閱了一些資料和本身的理解,把關於使用NPOI導出Word時所要涉及的一些段落,表格樣式作了相關注釋,和把段落和表格的建立實例,設置文字、字體、對齊方式都封裝了起了(爲了少寫代碼),文章末尾會附上一個完整的案例下載地址。git

1、首先引入NPOI NuGet:

版本說明:

  NPOI 2.4.1 (注意不一樣版本可能使用的姿式有點小差異)github

程序包管理器控制檯輸入一下命令安裝:

Install-Package NPOI -Version 2.4.1

經過NuGet管理解決方案安裝:

2、導出的Work文檔內容格式樣式:

 

3、NPOI中的XWPFRun文本對象建立和屬性簡單概述:

XWPFRun文本對象說明:

  XWPFRun是段落的文本對象,先建立段落對象纔可以在段落對象的基礎上建立文本對象,並設置相關文本樣式。框架

以下所示:學習

        /// <summary>
        /// 建立word文檔中的段落對象和設置段落文本的基本樣式(字體大小,字體,字體顏色,字體對齊位置)
        /// </summary>
        /// <param name="document">document文檔對象</param>
        /// <param name="fillContent">段落第一個文本對象填充的內容</param>
        /// <param name="isBold">是否加粗</param>
        /// <param name="fontSize">字體大小</param>
        /// <param name="fontFamily">字體</param>
        /// <param name="paragraphAlign">段落排列(左對齊,居中,右對齊)</param>
        /// <returns></returns>
        private static XWPFParagraph ParagraphInstanceSetting(XWPFDocument document, string fillContent, bool isBold, int fontSize, string fontFamily, ParagraphAlignment paragraphAlign,)
        {
            XWPFParagraph paragraph = document.CreateParagraph();//建立段落對象
            paragraph.Alignment = paragraphAlign;//文字顯示位置,段落排列(左對齊,居中,右對齊)

            XWPFRun xwpfRun = paragraph.CreateRun();//建立段落文本對象
            xwpfRun.IsBold = isBold;//文字加粗
            xwpfRun.SetText(fillContent);//填充內容
            xwpfRun.FontSize = fontSize;//設置文字大小
            xwpfRun.SetFontFamily(fontFamily, FontCharRange.None); //設置標題樣式如:(微軟雅黑,隸書,楷體)根據本身的需求而定
            return paragraph;
        }

 

XWPFRun文本對象的屬性比較多,如下我簡單說明經常使用的幾種方式:

            XWPFParagraph paragraph = document.CreateParagraph();//建立段落對象

            XWPFRun xwpfRun= paragraph.CreateRun();//建立段落文本對象
            xwpfRun.IsBold = isBold;//文字加粗
            xwpfRun.SetText(fillContent);//填充內容
            xwpfRun.FontSize = fontSize;//設置文字大小
            xwpfRun.SetFontFamily(fontFamily, FontCharRange.None); //設置標題樣式如:(微軟雅黑,隸書,楷體)根據本身的需求而定
            xwpfRun.SetColor("BED4F1");//設置字體顏色--十六進制
            xwpfRun.IsDoubleStrikeThrough=true;//是否顯示雙刪除線
            xwpfRun.IsStrikeThrough = true;//是否顯示單刪除線
            xwpfRun.SetUnderline(UnderlinePatterns.Dash);//設置下劃線,枚舉類型
            xwpfRun.SetTextPosition(20);//設置文本位置(設置兩行之間的行間)
            xwpfRun.AddBreak();//設置換行(</br>)
            xwpfRun.AddTab();//添加tab鍵
            xwpfRun.AddCarriageReturn();//添加回車鍵
            xwpfRun.IsImprinted = true;//印跡(懸浮陰影),效果和浮雕相似
            xwpfRun.IsItalic=true;//是否設置斜體(字體傾斜)
            xwpfRun.Subscript = VerticalAlign.SUBSCRIPT;//設置下標,枚舉類型

NPOI中關於XWPFRun屬性的更多使用技巧,請閱讀源碼:

源碼地址:https://github.com/tonyqus/npoi/blob/master/ooxml/XWPF/Usermodel/XWPFRun.cs字體

4、NPOI生成Word完整代碼:

using Microsoft.AspNetCore.Hosting;
using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.IO;

namespace Export.Services
{
    public class NpoiWordExportService
    {
        private static IHostingEnvironment _environment;

        public NpoiWordExportService(IHostingEnvironment iEnvironment)
        {
            _environment = iEnvironment;
        }

        #region 生成word

        /// <summary>
        ///  生成word文檔,並保存靜態資源文件夾(wwwroot)下的SaveWordFile文件夾中
        /// </summary>
        /// <param name="savePath">保存路徑</param>
        public bool SaveWordFile(out string savePath)
        {
            savePath = "";
            try
            {
                string currentDate = DateTime.Now.ToString("yyyyMMdd");
                string checkTime = DateTime.Now.ToString("yyyy年MM月dd日");//檢查時間
                //保存文件到靜態資源wwwroot,使用絕對路徑路徑
                var uploadPath = _environment.WebRootPath + "/SaveWordFile/" + currentDate + "/";//>>>至關於HttpContext.Current.Server.MapPath("") 

                string workFileName = checkTime + "追逐時光企業員工培訓考覈統計記錄表";
                string fileName = string.Format("{0}.docx", workFileName, System.Text.Encoding.UTF8);

                if (!Directory.Exists(uploadPath))
                {
                    Directory.CreateDirectory(uploadPath);
                }

                //經過使用文件流,建立文件流對象,向文件流中寫入內容,並保存爲Word文檔格式
                using (var stream = new FileStream(Path.Combine(uploadPath, fileName), FileMode.Create, FileAccess.Write))
                {
                    //建立document文檔對象對象實例
                    XWPFDocument document = new XWPFDocument();

                    /**
                     *這裏我經過設置公共的Word文檔中SetParagraph(段落)實例建立和段落樣式格式設置,大大減小了代碼的冗餘,
                     * 避免每使用一個段落而去建立一次段落實例和設置段落的基本樣式
                     *(以下,ParagraphInstanceSetting爲段落實例建立和樣式設置,後面索引表示爲當前是第幾行段落,索引從0開始)
                     */
                    //文本標題
                    document.SetParagraph(ParagraphInstanceSetting(document, workFileName, true, 19, "宋體", ParagraphAlignment.CENTER), 0);

                    //TODO:這裏一行須要顯示兩個文本
                    document.SetParagraph(ParagraphInstanceSetting(document, $"編號:20190927101120445887", false, 14, "宋體", ParagraphAlignment.CENTER, true, $"    檢查時間:{checkTime}"), 1);


                    document.SetParagraph(ParagraphInstanceSetting(document, "登記機關:企業員工監督檢查機構", false, 14, "宋體", ParagraphAlignment.LEFT), 2);


                    #region 文檔第一個表格對象實例
                    //建立文檔中的表格對象實例
                    XWPFTable firstXwpfTable = document.CreateTable(4, 4);//顯示的行列數rows:3行,cols:4列
                    firstXwpfTable.Width = 5200;//總寬度
                    firstXwpfTable.SetColumnWidth(0, 1300); /* 設置列寬 */
                    firstXwpfTable.SetColumnWidth(1, 1100); /* 設置列寬 */
                    firstXwpfTable.SetColumnWidth(2, 1400); /* 設置列寬 */
                    firstXwpfTable.SetColumnWidth(3, 1400); /* 設置列寬 */

                    //Table 表格第一行展現...後面的都是同樣,只改變GetRow中的行數
                    firstXwpfTable.GetRow(0).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "企業名稱", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(0).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "追逐時光", ParagraphAlignment.CENTER, 40, false));
                    firstXwpfTable.GetRow(0).GetCell(2).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "企業地址", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(0).GetCell(3).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "湖南省-長沙市-嶽麓區", ParagraphAlignment.CENTER, 40, false));

                    //Table 表格第二行
                    firstXwpfTable.GetRow(1).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "聯繫人", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(1).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "小明同窗", ParagraphAlignment.CENTER, 40, false));
                    firstXwpfTable.GetRow(1).GetCell(2).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "聯繫方式", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(1).GetCell(3).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "151****0456", ParagraphAlignment.CENTER, 40, false));


                    //Table 表格第三行
                    firstXwpfTable.GetRow(2).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "企業許可證號", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(2).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "XXXXX-66666666", ParagraphAlignment.CENTER, 40, false));
                    firstXwpfTable.GetRow(2).GetCell(2).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "檢查次數", ParagraphAlignment.CENTER, 40, true));
                    firstXwpfTable.GetRow(2).GetCell(3).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, $"本年度檢查8次", ParagraphAlignment.CENTER, 40, false));


                    firstXwpfTable.GetRow(3).MergeCells(0, 3);//合併3列
                    firstXwpfTable.GetRow(3).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "", ParagraphAlignment.LEFT, 10, false));

                    #endregion

                    var checkPeopleNum = 0;//檢查人數
                    var totalScore = 0;//總得分

                    #region 文檔第二個表格對象實例(遍歷表格項)
                    //建立文檔中的表格對象實例
                    XWPFTable secoedXwpfTable = document.CreateTable(5, 4);//顯示的行列數rows:8行,cols:4列
                    secoedXwpfTable.Width = 5200;//總寬度
                    secoedXwpfTable.SetColumnWidth(0, 1300); /* 設置列寬 */
                    secoedXwpfTable.SetColumnWidth(1, 1100); /* 設置列寬 */
                    secoedXwpfTable.SetColumnWidth(2, 1400); /* 設置列寬 */
                    secoedXwpfTable.SetColumnWidth(3, 1400); /* 設置列寬 */

                    //遍歷表格標題
                    secoedXwpfTable.GetRow(0).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "員工姓名", ParagraphAlignment.CENTER, 40, true));
                    secoedXwpfTable.GetRow(0).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "性別", ParagraphAlignment.CENTER, 40, true));
                    secoedXwpfTable.GetRow(0).GetCell(2).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "年齡", ParagraphAlignment.CENTER, 40, true));
                    secoedXwpfTable.GetRow(0).GetCell(3).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "綜合評分", ParagraphAlignment.CENTER, 40, true));

                    //遍歷四條數據
                    for (var i = 1; i < 5; i++)
                    {
                        secoedXwpfTable.GetRow(i).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "小明" + i + "", ParagraphAlignment.CENTER, 40, false));
                        secoedXwpfTable.GetRow(i).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, "", ParagraphAlignment.CENTER, 40, false));
                        secoedXwpfTable.GetRow(i).GetCell(2).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, 20 + i + "", ParagraphAlignment.CENTER, 40, false));
                        secoedXwpfTable.GetRow(i).GetCell(3).SetParagraph(SetTableParagraphInstanceSetting(document, firstXwpfTable, 90 + i + "", ParagraphAlignment.CENTER, 40, false));

                        checkPeopleNum++;
                        totalScore += 90 + i;
                    }

                    #endregion

                    #region 文檔第三個表格對象實例
                    //建立文檔中的表格對象實例
                    XWPFTable thirdXwpfTable = document.CreateTable(5, 4);//顯示的行列數rows:5行,cols:4列
                    thirdXwpfTable.Width = 5200;//總寬度
                    thirdXwpfTable.SetColumnWidth(0, 1300); /* 設置列寬 */
                    thirdXwpfTable.SetColumnWidth(1, 1100); /* 設置列寬 */
                    thirdXwpfTable.SetColumnWidth(2, 1400); /* 設置列寬 */
                    thirdXwpfTable.SetColumnWidth(3, 1400); /* 設置列寬 */
                    //Table 表格第一行,後面的合併3列(注意關於表格中行合併問題,先合併,後填充內容)
                    thirdXwpfTable.GetRow(0).MergeCells(0, 3);//從第一列起,合併3列
                    thirdXwpfTable.GetRow(0).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "檢查內容: " +
                        $"於{checkTime}下午檢查了追逐時光企業員工培訓考覈並對員工的相關信息進行了相關統計,統計結果以下:                                                                                                                                                                                                                " +
                        "-------------------------------------------------------------------------------------" +
                        $"共對該企業({checkPeopleNum})人進行了培訓考覈,培訓考覈總得分爲({totalScore})分。 " + "", ParagraphAlignment.LEFT, 30, false));


                    //Table 表格第二行
                    thirdXwpfTable.GetRow(1).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "檢查結果: ", ParagraphAlignment.CENTER, 40, true));
                    thirdXwpfTable.GetRow(1).MergeCells(1, 3);//從第二列起,合併三列
                    thirdXwpfTable.GetRow(1).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "該企業很是優秀,堅持天天學習打卡,具備蓬勃向上的活力。", ParagraphAlignment.LEFT, 40, false));

                    //Table 表格第三行
                    thirdXwpfTable.GetRow(2).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "處理結果: ", ParagraphAlignment.CENTER, 40, true));
                    thirdXwpfTable.GetRow(2).MergeCells(1, 3);
                    thirdXwpfTable.GetRow(2).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "經過檢查,評分爲優秀!", ParagraphAlignment.LEFT, 40, false));

                    //Table 表格第四行,後面的合併3列(注意關於表格中行合併問題,先合併,後填充內容),額外說明
                    thirdXwpfTable.GetRow(3).MergeCells(0, 3);//合併3列
                    thirdXwpfTable.GetRow(3).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "備註說明: 記住,堅持就是勝利,永遠保持一種求知,好問的心理!", ParagraphAlignment.LEFT, 30, false));

                    //Table 表格第五行
                    thirdXwpfTable.GetRow(4).MergeCells(0, 1);
                    thirdXwpfTable.GetRow(4).GetCell(0).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "                                                                                                                                                                                                 檢查人員簽名:              年 月 日", ParagraphAlignment.LEFT, 40, false));
                    thirdXwpfTable.GetRow(4).MergeCells(1, 2);

                    thirdXwpfTable.GetRow(4).GetCell(1).SetParagraph(SetTableParagraphInstanceSetting(document, thirdXwpfTable, "                                                                                                                                                                                                 企業法人簽名:              年 月 日", ParagraphAlignment.LEFT, 40, false));


                    #endregion

                    //向文檔流中寫入內容,生成word
                    document.Write(stream);

                    savePath = "/SaveWordFile/" + currentDate + "/" + fileName;

                    return true;
                }
            }
            catch (Exception ex)
            {
                //ignore
                savePath = ex.Message;
                return false;
            }
        }


        /// <summary>
        /// 建立word文檔中的段落對象和設置段落文本的基本樣式(字體大小,字體,字體顏色,字體對齊位置)
        /// </summary>
        /// <param name="document">document文檔對象</param>
        /// <param name="fillContent">段落第一個文本對象填充的內容</param>
        /// <param name="isBold">是否加粗</param>
        /// <param name="fontSize">字體大小</param>
        /// <param name="fontFamily">字體</param>
        /// <param name="paragraphAlign">段落排列(左對齊,居中,右對齊)</param>
        /// <param name="isStatement">是否在同一段落建立第二個文本對象(解決同一段落裏面須要填充兩個或者多個文本值的狀況,多個文本須要本身拓展,如今最多支持兩個)</param>
        /// <param name="secondFillContent">第二次聲明的文本對象填充的內容,樣式與第一次的一致</param>
        /// <returns></returns>
        private static XWPFParagraph ParagraphInstanceSetting(XWPFDocument document, string fillContent, bool isBold, int fontSize, string fontFamily, ParagraphAlignment paragraphAlign, bool isStatement = false, string secondFillContent = "")
        {
            XWPFParagraph paragraph = document.CreateParagraph();//建立段落對象
            paragraph.Alignment = paragraphAlign;//文字顯示位置,段落排列(左對齊,居中,右對齊)

            XWPFRun xwpfRun = paragraph.CreateRun();//建立段落文本對象
            xwpfRun.IsBold = isBold;//文字加粗
            xwpfRun.SetText(fillContent);//填充內容
            xwpfRun.FontSize = fontSize;//設置文字大小
            xwpfRun.SetFontFamily(fontFamily, FontCharRange.None); //設置標題樣式如:(微軟雅黑,隸書,楷體)根據本身的需求而定

            if (isStatement)
            {
                XWPFRun secondxwpfRun = paragraph.CreateRun();//建立段落文本對象
                secondxwpfRun.IsBold = isBold;//文字加粗
                secondxwpfRun.SetText(secondFillContent);//填充內容
                secondxwpfRun.FontSize = fontSize;//設置文字大小
                secondxwpfRun.SetFontFamily(fontFamily, FontCharRange.None); //設置標題樣式如:(微軟雅黑,隸書,楷體)根據本身的需求而定
            }


            return paragraph;
        }

        /// <summary>  
        /// 建立Word文檔中表格段落實例和設置表格段落文本的基本樣式(字體大小,字體,字體顏色,字體對齊位置)
        /// </summary>  
        /// <param name="document">document文檔對象</param>  
        /// <param name="table">表格對象</param>  
        /// <param name="fillContent">要填充的文字</param>  
        /// <param name="paragraphAlign">段落排列(左對齊,居中,右對齊)</param>
        /// <param name="rowsHeight">設置文本位置(設置兩行之間的行間),從而實現table的高度設置效果  </param>
        /// <param name="isBold">是否加粗(true加粗,false不加粗)</param>
        /// <param name="fontSize">字體大小</param>
        /// <returns></returns>  
        private static XWPFParagraph SetTableParagraphInstanceSetting(XWPFDocument document, XWPFTable table, string fillContent, ParagraphAlignment paragraphAlign, int rowsHeight, bool isBold, int fontSize = 10)
        {
            var para = new CT_P();
            XWPFParagraph paragraph = new XWPFParagraph(para, table.Body);//建立表格中的段落對象
            paragraph.Alignment = paragraphAlign;//文字顯示位置,段落排列(左對齊,居中,右對齊)

            XWPFRun xwpfRun = paragraph.CreateRun();//建立段落文本對象
            xwpfRun.SetText(fillContent);
            xwpfRun.FontSize = fontSize;//字體大小
            xwpfRun.IsBold = isBold;//是否加粗
            xwpfRun.SetFontFamily("宋體", FontCharRange.None);//設置字體(如:微軟雅黑,華文楷體,宋體)
            xwpfRun.SetTextPosition(rowsHeight);//設置文本位置(設置兩行之間的行間),從而實現table的高度設置效果 
            return paragraph;
        }

        #endregion


    }
}

總結:

  寫到最後我只想說我太難了,爲了實現我想要的這個樣式,經過不斷的查閱資料,理解NPOI中的段落,文本基本屬性。最終在我生成第22個word時,總算是達到了我要的效果。這裏我將本身在網上查閱的一些資料和本身的實踐心得分享給你們,但願可以幫到你們,別忘了給我star喲。spa

GitHub完整示例地址:https://github.com/YSGStudyHards/NPOI-Export-Word  code

相關文章
相關標籤/搜索