C# 生成word文檔(NPOI.XWPF)


一、基礎

1、創建Word

using NPOI.XWPF.UserModel
        XWPFDocument doc = new XWPFDocument();      //創建新的word文檔
        
        XWPFParagraph p1 = doc.CreateParagraph();   //向新文檔中添加段落
        p1.SetAlignment(ParagraphAlignment.CENTER); //段落對其方式為居中

        XWPFRun r1 = p1.CreateRun();                //向該段落中添加文字
        r1.SetText("測試段落一");

        XWPFParagraph p2 = doc.CreateParagraph();
        p2.SetAlignment(ParagraphAlignment.LEFT);

        XWPFRun r2 = p2.CreateRun();
        r2.SetText("測試段落二");
     r2.SetFontSize(16);//設置字體大小
       r2.SetBlod(true);//設置粗體

        FileStream sw = File.Create("cutput.docx"); //...
        doc.Write(sw);                              //...
        sw.Close();                                 //在服務端生成文件

        FileInfo file = new FileInfo("cutput.docx");//文件保存路徑及名稱  
                                                    //注意: 文件保存的父文件夾需添加Everyone用戶,並給予其完全控制權限
        Response.Clear();
        Response.ClearHeaders();
        Response.Buffer = false;
        Response.ContentType = "application/octet-stream";
        Response.AppendHeader("Content-Disposition", "attachment;filename=" 
            + HttpUtility.UrlEncode("output.docx", System.Text.Encoding.UTF8));
        Response.AppendHeader("Content-Length", file.Length.ToString());
        Response.WriteFile(file.FullName);
        Response.Flush();                           //以上將生成的word文件發送至用戶瀏覽器

        File.Delete("cutput.docx");

2、特殊字符

代碼實現起來很簡單。

run之前的代碼就不寫了。大家可以網上搜索。

run.FontFamily = "Wingdings 2";//這邊是特殊字符的字體
text = text.Replace("name", Convert.ToChar(0x0052).ToString());//0x0052是特殊字符的十六進制代碼
//text = text.Replace("name", "R");//該代碼也可以實現(0x0052對應的字符就是R)

3、NOPI讀取Word模板並渲染保存

using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;


namespace TestNPOI
{
    public class NPOIHleper
    {

        public static void Export()
        {
            string filepath = HttpContext.Current.Server.MapPath("~/simpleTable.docx");
            var tt = new  { name = "cjc", age = 29 };
            using (FileStream stream = File.OpenRead(filepath))
            {
                XWPFDocument doc = new XWPFDocument(stream);
                //遍歷段落                  
                foreach (var para in doc.Paragraphs)
                {
                    ReplaceKey(para, tt);
                }                    //遍歷表格      
                var tables = doc.Tables;
                foreach (var table in tables)
                {
                    foreach (var row in table.Rows)
                    {
                        foreach (var cell in row.GetTableCells())
                        {
                            foreach (var para in cell.Paragraphs)
                            {
                                ReplaceKey(para, tt);
                            }
                        }
                    }
                }

                FileStream out1 = new FileStream(HttpContext.Current.Server.MapPath("~/simpleTable" + DateTime.Now.Ticks + ".docx"), FileMode.Create);
                doc.Write(out1);
                out1.Close();
            }
        }

        private static void ReplaceKey(XWPFParagraph para, object model)
        {
            string text = para.ParagraphText;
            var runs = para.Runs;
            string styleid = para.Style;
            for (int i = 0; i < runs.Count; i++)
            {
                var run = runs[i];
                text = run.ToString();
                Type t = model.GetType();
                PropertyInfo[] pi = t.GetProperties();
                foreach (PropertyInfo p in pi)
                {
                    //$$與模板中$$對應,也可以改成其它符號,比如{$name},務必做到唯一
                    if (text.Contains("$" + p.Name + "$"))
                    {
                        text = text.Replace("$" + p.Name + "$", p.GetValue(model, null).ToString());
                    }
                }
                runs[i].SetText(text, 0);
            }
        }

    }
}

 

模板:

111

結果:

222

 

二、實踐(渲染Word模板、插入特殊字符、指定表格位置插入行)

1、項目搭建

1、創建項目

2、創建類庫和引入NPOI

 

 報錯

  報搜嘗試解決方案一

在項目下面建立upload文件夾,然后使用相對路徑訪問。

 在其他目錄下請把upload目錄權限授予 asp.net用戶。

 

 最后直接暴力EveryOney  也無效,找到的原因是參數位置搞錯了,文件名+路徑最后改為 路徑+文件名的方式
 

3、貼上代碼

using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;

namespace NPOITest
{
    public class NPOIHleper
    {


        /// <summary>
        /// 輸出模板docx文檔
        /// </summary>
        /// <param name="tempFilePath">模板文件地址</param>
        /// <param name="outFolder">輸出文件夾</param >
        /// <param name="fileName">文件名</param>
        /// <param name="data">數據格式Json->new { name = "cjc", age = 29 }</param>
        public static void CreateWord(string tempFilePath, string outFolder, string fileName, object data)
        {
            using (FileStream stream = File.OpenRead(tempFilePath))
            {
                XWPFDocument doc = new XWPFDocument(stream);
                //遍歷段落                  
                foreach (var para in doc.Paragraphs)
                {
                    ReplaceKey(para, data);
                }   //遍歷表格      
                var tables = doc.Tables;
                foreach (var table in tables)
                {
                    foreach (var row in table.Rows)
                    {
                        foreach (var cell in row.GetTableCells())
                        {
                            foreach (var para in cell.Paragraphs)
                            {
                                ReplaceKey(para, data);
                            }
                        }
                    }
                }
                var fullPath = Path.Combine(outFolder, fileName);
                FileStream outFile = new FileStream(fullPath, FileMode.Create);
                doc.Write(outFile);
                outFile.Close();
            }
        }
        /// <summary>
        /// 遍歷替換段落位置字符
        /// </summary>
        /// <param name="para">段落參數</param>
        /// <param name="model">數據</param>
        private static void ReplaceKey(XWPFParagraph para, object model)
        {
            string text = para.ParagraphText;
            var runs = para.Runs;
            string styleid = para.Style;
            for (int i = 0; i < runs.Count; i++)
            {
                var run = runs[i];
                text = run.ToString();
                Type t = model.GetType();
                PropertyInfo[] pi = t.GetProperties();
                foreach (PropertyInfo p in pi)
                {
                    //$$與模板中$$對應,也可以改成其它符號,比如{$name},務必做到唯一
                    if (text.Contains("{$"+p.Name+"}"))
                    {
                        text = text.Replace("{$" + p.Name+"}", p.GetValue(model, null).ToString());
                    }
                }
                runs[i].SetText(text, 0);
            }
        }
    }
}

調用方式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace NPOITest.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var  data = new  { name = "cjc", age = 29 };
            string fileName = Guid.NewGuid() + "_聲明.docx";
            string folder = Server.MapPath("~/upload"); //當前運行環境
            string tempTemplateFile = folder+"/測試.docx";
            string folders = "D:\\TempFile"; //當前運行環境
            NPOIHleper.CreateWord(tempTemplateFile, folders, fileName, data);
            //
            ViewBag.Title = "Home Page";

            return View();
        }
    }
}

對應模板

 

三、實踐(指定表格位置插入行)

代碼:

using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;

namespace NPOITest
{
    public class NPOIHleper
    {


        /// <summary>
        /// 輸出模板docx文檔
        /// </summary>
        /// <param name="tempFilePath">模板文件地址</param>
        /// <param name="outFolder">輸出文件夾</param >
        /// <param name="fileName">文件名</param>
        /// <param name="data">數據格式Json->new { name = "cjc", age = 29 }</param>
        public static void CreateWord(string tempFilePath, string outFolder, string fileName, object data)
        {
            using (FileStream stream = File.OpenRead(tempFilePath))
            {
                XWPFDocument doc = new XWPFDocument(stream);
                //遍歷段落                  
                foreach (var para in doc.Paragraphs)
                {
                    ReplaceKey(para, data);
                }   //遍歷表格      
                var tables = doc.Tables;
                foreach (var table in tables)
                {
                    foreach (var row in table.Rows)
                    {
                        foreach (var cell in row.GetTableCells())
                        {
                            foreach (var para in cell.Paragraphs)
                            {
                                ReplaceKey(para, data);
                            }
                        }
                    }
                }
                //單獨對表格新增
                var oprTable = tables[1];


                XWPFTableRow m_Row=oprTable.InsertNewTableRow(1);//創建一行/並且在某個位置添加一行
                m_Row.AddNewTableCell().SetText ("創建一行僅有一個單元格");


                //XWPFTableRow m_Row2 = oprTable.InsertNewTableRow(2);//創建一行/並且在某個位置添加一行
                ////m_Row2.AddNewTableCell().SetText("添加的新行");
                //XWPFTableCell cellCt_P = m_Row2.CreateCell();//創建一個單元格,創建單元格時就創建了一個CT_P

                //cellCt_P = m_Row2.CreateCell();
                //cellCt_P = m_Row2.CreateCell();

                ////單元格行和表
                //CT_Tc cttc = cellCt_P.GetCTTc();
                //CT_TcPr ctPr = cttc.AddNewTcPr();
                ////ctPr.gridSpan.val = "3";//合並3列
                //ctPr.AddNewVMerge().val = ST_Merge.restart;//合並行
                //cellCt_P.SetText("創建一行僅有一個單元格(合並后)");


                XWPFTableRow m_Row2 = oprTable.InsertNewTableRow(2);//創建一行/並且在某個位置添加一行
                XWPFTableCell tc3 = m_Row2.CreateCell();//創建單元格
                tc3.SetText("創建一行僅有一個單元格(合並后)");
                CT_Tc ct3 = tc3.GetCTTc();
                CT_TcPr cp3 = ct3.AddNewTcPr();
                cp3.gridSpan = new CT_DecimalNumber();
                cp3.gridSpan.val = "3"; //合並3列   


                XWPFTableRow m_Row3 = oprTable.InsertNewTableRow(2);//多個單元格以及合並
                m_Row3.AddNewTableCell().SetText("添加的新行單元格1");
                m_Row3.AddNewTableCell().SetText("添加的新行單元格2");
                m_Row3.AddNewTableCell().SetText("添加的新行單元格3");


                var fullPath = Path.Combine(outFolder, fileName);
                FileStream outFile = new FileStream(fullPath, FileMode.Create);
                doc.Write(outFile);
                outFile.Close();
            }
        }
        /// <summary>
        /// 遍歷替換段落位置字符
        /// </summary>
        /// <param name="para">段落參數</param>
        /// <param name="model">數據</param>
        private static void ReplaceKey(XWPFParagraph para, object model)
        {
            string text = para.ParagraphText;
            var runs = para.Runs;
            string styleid = para.Style;
            for (int i = 0; i < runs.Count; i++)
            {
                var run = runs[i];
                text = run.ToString();
                Type t = model.GetType();
                PropertyInfo[] pi = t.GetProperties();
                foreach (PropertyInfo p in pi)
                {
                    //$$與模板中$$對應,也可以改成其它符號,比如{$name},務必做到唯一
                    if (text.Contains("{$" + p.Name + "}"))
                    {
                        text = text.Replace("{$" + p.Name + "}", p.GetValue(model, null).ToString());
                    }
                }
                runs[i].SetText(text, 0);
            }
        }
    }
}

結果:

 

 

 

四、實踐(指定表格內單元格(字體)下划線+字符)

簡單說明:

                XWPFParagraph p1 = doc.CreateParagraph(); //段落
                XWPFRun _run = p1.CreateRun();
                _run.SetText("一個單元格");
                _run.SetUnderline(UnderlinePatterns.Single);//段落下划線

既有文字加文字(下划線)

                XWPFTableRow m_Row2 = oprTable.InsertNewTableRow(2);//創建一行/並且在某個位置添加一行
                XWPFTableCell tc3 = m_Row2.CreateCell();//創建單元格
                //tc3.SetText("創建一行僅有一個單元格(合並后)");

                XWPFParagraph p1 = doc.CreateParagraph(); //段落
                XWPFRun _run = p1.CreateRun();
                _run.SetText("一個單元格");
                _run.SetUnderline(UnderlinePatterns.Single);//段落

                XWPFParagraph p12 = doc.CreateParagraph(); //無段落
                XWPFRun _run2 = p1.CreateRun();
                _run2.SetText("一個單元格");


                tc3.SetParagraph(p1);

 

 

這種寫法我發現別扭,應該為

                //單獨對表格新增
                var oprTable = tables[1];

                XWPFTableRow m_Row2 = oprTable.InsertNewTableRow(2);//創建一行/並且在某個位置添加一行
                XWPFTableCell tc3 = m_Row2.CreateCell();//創建單元格

                XWPFParagraph p1 = doc.CreateParagraph(); //段落1開始  1、注意這個段落是Doc創建的會導致表格外有段落出現
                XWPFRun _run = p1.CreateRun();
                _run.SetText("下划線");
                _run.SetUnderline(UnderlinePatterns.Single);//段落1結束

                //_run.AddCarriageReturn();2、注意只對表格外換行有效
                XWPFRun _run2 = p1.CreateRun();
                _run2.SetText("#####");

                tc3.SetParagraph(p1);

  發現我需要換行,思路還是不對,經過我讀取拿到文檔的數據結構,即表格的XWPFTableCell單元格paragraph屬性如下:

 

經更改

 

                //單獨對表格新增
                var oprTable = tables[1];

                XWPFTableRow m_Row2 = oprTable.InsertNewTableRow(2);//創建一行/並且在某個位置添加一行
                XWPFTableCell tc3 = m_Row2.CreateCell();//創建單元格

                XWPFParagraph p1 = tc3.AddParagraph();
                XWPFRun _run = p1.CreateRun();
                _run.SetText("下划線");
                _run.SetUnderline(UnderlinePatterns.Single);//段落1結束

                //_run.AddCarriageReturn();2、注意只對表格外換行有效
                XWPFParagraph p2 = tc3.AddParagraph();
                XWPFRun _run2 = p2.CreateRun();
                _run2.SetText("####");

                //這里設置了一下 //在復制這個就無效了 tc3.SetParagraph(p1); 想要添加通過(add方式)tc3.AddParagraph();
                tc3.SetParagraph(p1);

 

五、實踐出現模板渲染替換問題

解決辦法:刪掉->重新寫->可以從記事本復制

 

 

 其他妙用

//新建段落     

XWPFParagraph p1 = doc.CreateParagraph();

//對齊方式

 p1.SetAlignment(ParagraphAlignment.LEFT);

p1.SetVerticalAlignment(TextAlignment.AUTO);

//Word邊框樣式

p1.SetBorderBottom(Borders.DOUBLE);
p1.SetBorderTop(Borders.DOUBLE);
p1.SetBorderRight(Borders.DOUBLE);
p1.SetBorderLeft(Borders.DOUBLE);

p1.SetBorderBetween(Borders.SINGLE);

            //新建文字

            XWPFRun rUserHead = p1.CreateRun();

//文字內容

            rUserHead.SetText("員工 : ");

//顏色

            rUserHead.SetColor("4F6B72");

//大小

            rUserHead.SetFontSize(15);

//是否加粗

            rUserHead.SetBold(true);

//字體

            rUserHead.SetFontFamily("宋體");

//是否有下划線

            //r1.SetUnderline(UnderlinePatterns.DotDotDash);

//位置

            rUserHead.SetTextPosition(20);

//增加換行

rUserHead.AddCarriageReturn();

 

需求整理(動態在某個單元格內插入多個字段)

1、原本樣子以及要實現的效果

 實現的效果

原因:

 

需求整理(動態插入表格)

1、原本樣子以及要實現的效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM