一、基礎
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); } } } }
模板:
結果:
二、實踐(渲染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、原本樣子以及要實現的效果