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();//设置字体大小
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 = };
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 = ; 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, );
}
} }
}
模板:
结果:
二、实践(渲染Word模板、插入特殊字符、指定表格位置插入行)
1、项目搭建
1、创建项目
2、创建类库和引入NPOI
报错
报搜尝试解决方案一
在项目下面建立upload文件夹,然后使用相对路径访问。


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 = ; 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, );
}
}
}
}
调用方式
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 = };
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[]; XWPFTableRow m_Row=oprTable.InsertNewTableRow();//创建一行/并且在某个位置添加一行
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();//创建一行/并且在某个位置添加一行
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列 XWPFTableRow m_Row3 = oprTable.InsertNewTableRow();//多个单元格以及合并
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 = ; 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, );
}
}
}
}
结果:

四、实践(指定表格内单元格(字体)下划线+字符)
简单说明:
XWPFParagraph p1 = doc.CreateParagraph(); //段落
XWPFRun _run = p1.CreateRun();
_run.SetText("一个单元格");
_run.SetUnderline(UnderlinePatterns.Single);//段落下划线
既有文字加文字(下划线)
XWPFTableRow m_Row2 = oprTable.InsertNewTableRow();//创建一行/并且在某个位置添加一行
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[]; XWPFTableRow m_Row2 = oprTable.InsertNewTableRow();//创建一行/并且在某个位置添加一行
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(); //是否加粗 rUserHead.SetBold(true); //字体 rUserHead.SetFontFamily("宋体"); //是否有下划线 //r1.SetUnderline(UnderlinePatterns.DotDotDash); //位置 rUserHead.SetTextPosition(); //增加换行 rUserHead.AddCarriageReturn();
需求整理(动态在某个单元格内插入多个字段)
1、原本样子以及要实现的效果
实现的效果
原因:
需求整理(动态插入表格)
1、原本样子以及要实现的效果
C# 生成word文档(NPOI.XWPF)的更多相关文章
- PoiDocxDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0),目前只能java生成】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个是<PoiDemo[Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)]>的扩展,上一篇是根 ...
- PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用Poi实现android中根据模板文件生成Word文档的功能.这里的模板文件是doc文件.如果模板文件是docx文件的话,请阅读 ...
- Aspose.Words简单生成word文档
Aspose.Words简单生成word文档 Aspose.Words.Document doc = new Aspose.Words.Document(); Aspose.Words.Documen ...
- ASP.NET生成WORD文档,服务器部署注意事项
网上转的,留查备用,我服务器装的office2007所以修改的是Microsoft Office word97 - 2003 文档这一个. ASP.NET生成WORD文档服务器部署注意事项 1.Asp ...
- POI生成WORD文档
h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...
- PowerDesigner将PDM导出生成WORD文档
PowerDesigner将PDM导出生成WORD文档 环境 PowerDesigner15 1.点击Report Temlates 制作模板 2.如果没有模板,单击New图标创建.有直接双击进入. ...
- velocity模板技术生成word文档
本文介绍採用velocity技术在Java中生成word文档的方法. 1.新建一个word文档,编辑内容例如以下: 2.将上述word文档另存为htm格式的文件 3.新建一个Java Project项 ...
- 使用C#动态生成Word文档/Excel文档的程序测试通过后,部署到IIS服务器上,不能正常使用的问题解决方案
使用C#动态生成Word文档/Excel文档的程序功能调试.测试通过后,部署到服务器上,不能正常使用的问题解决方案: 原因: 可能asp.net程序或iis访问excel组件时权限不够(Ps:Syst ...
- 用php生成word文档
一.用windows里面自带的com,然后用php生成word文档 <?php $word= new COM("word.application") or die(" ...
- c#生成word文档
参考:http://blog.163.com/zhouchunping_99/blog/static/7837998820085114394716/ 生成word文档 生成word文档 view pl ...
随机推荐
- spring boot 集成 websocket 实现消息主动推送
spring boot 集成 websocket 实现消息主动 前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单 ...
- 【leetcode】1028. Recover a Tree From Preorder Traversal
题目如下: We run a preorder depth first search on the root of a binary tree. At each node in this traver ...
- HashMap测试程序1
package com.iotek.map; import java.util.Collection;import java.util.HashMap;import java.util.Map;imp ...
- 持续优化云原生体验,阿里云在Serverless容器与多云上的探索
近日,阿里云宣布推出Serverless Kubernetes服务此举意在降低容器技术的使用门槛.简化容器平台运维.并同时发布阿里云服务对Open Service Broker API标准支持,通过一 ...
- php strlen()函数 语法
php strlen()函数 语法 作用:返回字符串的长度.大理石平台价格 语法:strlen(string) 参数: 参数 描述 string 必需.规定要检查的字符串. 说明:返回字符串的 ...
- [USACO16JAN]愤怒的奶牛Angry Cows (单调队列优化dp)
题目链接 Solution 应该可以用二分拿部分分,时间 \(O(n^2logn)\) . 然后可以考虑 \(n^2\) \(dp\) ,令 \(f_i\) 代表 \(i\) 点被激活,然后激活 \( ...
- 20180826(05)- Java URL处理
Java URL处理 URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址.表示为互联网上的资源,如网页或者FTP地址. 本章节我们将介绍Java是 ...
- 牛客多校第一场 Random Point in Triangle
https://ac.nowcoder.com/acm/contest/881/F 打表代码: #include<bits/stdc++.h> using namespace std; ] ...
- python-zx笔记10-断言
断言 断言内容是自动化脚本的重要内容,正确设置断言以后才能帮助我们判断测试用例执行结果. 断言方法 assertEqual(a, b) 判断a==b assertNotEqual(a, b) 判断a! ...
- jinjia2 模板学习
参考链接https://blog.csdn.net/langkew/article/details/51734423