.net core 3.1框架引用NPOI动态导出World文档,包含分页、单元格合并基本功能
1.引用第三方库NPOI
![在这里插入图片描述]
动态生成表格实体类
using ExportWorld.Utility;
using Newtonsoft.Json.Linq;
using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
namespace ExportWorld
{
public class SaveWorld
{
/// <summary>
/// 外部调用
/// </summary>
/// <param name="title"></param>
/// <param name="subTitle"></param>
/// <param name="headInfo"></param>
/// <param name="dt"></param>
/// <param name="footInfo"></param>
/// <param name="page">页数(测试用)</param>
public static void Show(string title, string subTitle, JObject headInfo, DataTable dt, JObject footInfo, int page)
{
string workFileName = "入库单8";
var uploadPath = @"D:\C#Test\ExportWorld\Save";
string fileName = string.Format("{0}.docx", workFileName, System.Text.Encoding.UTF8);
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);
}
using (var stream = new FileStream(Path.Combine(uploadPath, fileName), FileMode.Create, FileAccess.Write))
{
//创建document文档对象对象实例
XWPFDocument document = new XWPFDocument();
document.Document.body.sectPr = new CT_SectPr();
CT_SectPr m_SectPr = document.Document.body.sectPr;
//页面设置A4横向
m_SectPr.pgSz.w = (ulong)16838;
m_SectPr.pgSz.h = (ulong)11906;
#region 创建表格
FillWorldData(document, title, subTitle, headInfo, dt, footInfo);
//测试分页
if (page != 0)
{
XWPFParagraph xWPFParagraph = document.CreateParagraph();
xWPFParagraph.CreateRun().AddBreak();//分页
FillWorldData(document, title, subTitle, headInfo, dt, footInfo);
}
#region 页脚
CT_Ftr m_ftr = new CT_Ftr();
m_ftr.Items = new System.Collections.ArrayList();
CT_SdtBlock m_Sdt = new CT_SdtBlock();
CT_SdtPr m_SdtPr = m_Sdt.AddNewSdtPr();
CT_SdtDocPart m_SdtDocPartObj = m_SdtPr.AddNewDocPartObj();
m_SdtDocPartObj.AddNewDocPartGallery().val = "PageNumbers (Bottom of Page)";
m_SdtDocPartObj.docPartUnique = new CT_OnOff();
CT_SdtContentBlock m_SdtContent = m_Sdt.AddNewSdtContent();
CT_P m_SdtContentP = m_SdtContent.AddNewP();
CT_PPr m_SdtContentPpPr = m_SdtContentP.AddNewPPr();
m_SdtContentPpPr.AddNewJc().val = ST_Jc.center;
m_SdtContentP.Items = new System.Collections.ArrayList();
CT_SimpleField m_fldSimple = new CT_SimpleField();
m_fldSimple.instr = " PAGE \\*MERGEFORMAT ";
m_SdtContentP.Items.Add(m_fldSimple);
m_ftr.Items.Add(m_Sdt);
XWPFRelation Frelation = XWPFRelation.FOOTER;
XWPFFooter m_f = (XWPFFooter)document.CreateRelationship(Frelation, XWPFFactory.GetInstance(), document.FooterList.Count + 1);
m_f.SetHeaderFooter(m_ftr);
CT_HdrFtrRef m_HdrFtr = m_SectPr.AddNewFooterReference();
m_HdrFtr.type = ST_HdrFtr.@default;
m_HdrFtr.id = m_f.GetPackageRelationship().Id;
#endregion
document.Write(stream);
#endregion
}
}
/// <summary>
/// 合并区域(有问题)
/// </summary>
/// <param name="table"></param>
/// <param name="fromCol"></param>
/// <param name="toCol"></param>
/// <param name="fromRow"></param>
/// <param name="toRow"></param>
private static void MyMergeCells(XWPFTable table, int fromCol,int toCol, int fromRow, int toRow)
{
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++)
{
if (fromCol < toCol)
{
table.GetRow(rowIndex).MergeCells(fromCol, toCol);//合并列
}
XWPFTableCell cell = table.GetRow(rowIndex).GetCell(fromCol);
CT_Tc cttc = cell.GetCTTc();
if (cttc.tcPr == null)
{
cttc.AddNewTcPr();
}
//第一个合并单元格用重启合并值设置
if (rowIndex == fromRow)
{
cell.GetCTTc().AddNewTcPr().AddNewVMerge().val = ST_Merge.restart;
}
else
{
//合并第一个单元格的单元被设置为“继续”
cell.GetCTTc().AddNewTcPr().AddNewVMerge().val = ST_Merge.@continue;
}
}
}
/// <summary>
/// 动态生成表格填充数据
/// </summary>
/// <param name="document"></param>
/// <param name="title">标题</param>
/// <param name="subTitle">副标题</param>
/// <param name="headInfo">表格头部信息</param>
/// <param name="dt">表格中间数据集</param>
/// <param name="footInfo">表格底部信息</param>
/// <param name="fontColor">字体颜色</param>
/// <returns></returns>
public static string FillWorldData(XWPFDocument document, string title, string subTitle, JObject headInfo, DataTable dt, JObject footInfo, string fontColor = "000000")
{
try
{
int rows = 0, cols = 0, index = 0, temp = 0, startRow = 0, count=1;
if (!string.IsNullOrWhiteSpace(title))
rows += 1;
if (!string.IsNullOrWhiteSpace(subTitle))
rows += 1;
if (headInfo != null && headInfo.Count > 0)
{
count += ((headInfo.Count) % 2 == 1 ? headInfo.Count / 2 : headInfo.Count / 2 - 1);
rows += count;
}
if (footInfo != null && footInfo.Count > 0)
{
count = 1;
count += ((footInfo.Count) % 2 == 1 ? footInfo.Count / 2 : footInfo.Count / 2 - 1);
rows += count;
}
if (dt != null && dt.Rows.Count > 0)
{
rows += dt.Rows.Count;
cols += dt.Columns.Count;
}
XWPFTable firstXwpfTable = document.CreateTable(rows, cols);//创建表格
firstXwpfTable.Width = 5500;//总宽度
if (!string.IsNullOrWhiteSpace(title.Trim()))
{
firstXwpfTable.GetRow(startRow).MergeCells(0, cols - 1);//合并列
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, title, ParagraphAlignment.CENTER, 24, true, 22, fontColor));//标题
startRow++;
}
if (!string.IsNullOrWhiteSpace(subTitle.Trim()))
{
firstXwpfTable.GetRow(startRow).MergeCells(0, cols - 1);//合并列
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, subTitle, ParagraphAlignment.CENTER, 24, true, 16, fontColor));//附标题
startRow++;
}
if (headInfo != null && headInfo.Count > 0)//头部
{
foreach (var item in headInfo)
{
temp = startRow;
if (index % 2 == 0)
{
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Key, ParagraphAlignment.CENTER, 24, true, 10, fontColor));
firstXwpfTable.GetRow(startRow).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Value.ToString(), ParagraphAlignment.CENTER, 24, false, 10, fontColor));
}
else
{
firstXwpfTable.GetRow(startRow).GetCell(cols - 2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Key, ParagraphAlignment.CENTER, 24, true));
firstXwpfTable.GetRow(startRow).GetCell(cols - 1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Value.ToString(), ParagraphAlignment.CENTER, 24, false, 10, fontColor));
if (!index.Equals(headInfo.Count - 1))
{
startRow++;
}
}
index++;
}
//MyMergeCells(firstXwpfTable, 2, cols-3,startRow-1, temp + ((index % 2) == 1 ? index / 2 : index / 2 - 1)-1);//合并区域
startRow++;
}
if (dt != null && dt.Rows.Count > 0)//中间数据
{
if (headInfo != null && headInfo.Count > 0)
{
//合并单元格
firstXwpfTable.GetRow(startRow).MergeCells(0, cols - 1);//合并
startRow++;
}
for (int j = 0; j < dt.Columns.Count; j++)
{
firstXwpfTable.GetRow(startRow).GetCell(j).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, dt.Columns[j].ToString(), ParagraphAlignment.CENTER, 24, true, 10, fontColor));//列名加粗
}
startRow++;
for (int i = 0; i < dt.Rows.Count; i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
firstXwpfTable.GetRow(startRow).GetCell(j).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, dt.Rows[i][j].ToString(), ParagraphAlignment.CENTER, 24, false, 10, fontColor));
}
if (i == dt.Rows.Count - 1)
{
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, dt.Rows[i][0].ToString(), ParagraphAlignment.CENTER, 24, true, 10, fontColor));//最后一行列名加粗
}
startRow++;
}
}
if (footInfo != null && footInfo.Count > 0)//尾部
{
if (dt != null && dt.Rows.Count > 0)
{
firstXwpfTable.GetRow(startRow).MergeCells(0, cols - 1);//合并
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, "", ParagraphAlignment.LEFT, 10, false, 10, fontColor));
startRow++;
}
index = 0;
foreach (var item in footInfo)
{
temp = startRow;
if (index % 2 == 0)
{
firstXwpfTable.GetRow(startRow).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Key, ParagraphAlignment.CENTER, 24, true));
firstXwpfTable.GetRow(startRow).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Value.ToString(), ParagraphAlignment.CENTER, 24, false, 10, fontColor));
}
else
{
firstXwpfTable.GetRow(startRow).GetCell(cols - 2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Key, ParagraphAlignment.CENTER, 24, true));
firstXwpfTable.GetRow(startRow).GetCell(cols - 1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, firstXwpfTable, item.Value.ToString(), ParagraphAlignment.CENTER, 24, false, 10, fontColor));
if (!index.Equals(footInfo.Count - 1))
{
startRow++;
}
}
index++;
}
//MyMergeCells(firstXwpfTable, 2, 1,startRow, temp + ((index % 2) == 1 ? index / 2 : index / 2 - 1));//合并区域
}
}
catch (Exception ex)
{
return ex.Message;
}
return "";
}
}
}
生成wrold文本样式
using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.Text;
namespace ExportWorld.Utility
{
public class NpoiWordParagraphTextStyleHelper
{
private static NpoiWordParagraphTextStyleHelper _exportHelper;
public static NpoiWordParagraphTextStyleHelper _
{
get => _exportHelper ?? (_exportHelper = new NpoiWordParagraphTextStyleHelper());
set => _exportHelper = value;
}
/// <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>
/// <param name="fontColor">字体颜色--十六进制</param>
/// <param name="isItalic">是否设置斜体(字体倾斜)</param>
/// <returns></returns>
public XWPFParagraph ParagraphInstanceSetting(XWPFDocument document, string fillContent, bool isBold, int fontSize, string fontFamily, ParagraphAlignment paragraphAlign, bool isStatement = false, string secondFillContent = "", string fontColor = "000000", bool isItalic = false)
{
XWPFParagraph paragraph = document.CreateParagraph();//创建段落对象
paragraph.Alignment = paragraphAlign;//文字显示位置,段落排列(左对齐,居中,右对齐)
XWPFRun xwpfRun = paragraph.CreateRun();//创建段落文本对象
xwpfRun.IsBold = isBold;//文字加粗
xwpfRun.SetText(fillContent);//填充内容
xwpfRun.FontSize = fontSize;//设置文字大小
xwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
xwpfRun.SetFontFamily(fontFamily, FontCharRange.None); //设置标题样式如:(微软雅黑,隶书,楷体)根据自己的需求而定
if (!isStatement) return paragraph;
XWPFRun secondXwpfRun = paragraph.CreateRun();//创建段落文本对象
secondXwpfRun.IsBold = isBold;//文字加粗
secondXwpfRun.SetText(secondFillContent);//填充内容
secondXwpfRun.FontSize = fontSize;//设置文字大小
secondXwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
secondXwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
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="textPosition">设置文本位置(设置两行之间的行间,从而实现表格文字垂直居中的效果),从而实现table的高度设置效果 </param>
/// <param name="isBold">是否加粗(true加粗,false不加粗)</param>
/// <param name="fontSize">字体大小</param>
/// <param name="fontColor">字体颜色--十六进制</param>
/// <param name="isItalic">是否设置斜体(字体倾斜)</param>
/// <returns></returns>
public XWPFParagraph SetTableParagraphInstanceSetting(XWPFDocument document, XWPFTable table, string fillContent, ParagraphAlignment paragraphAlign, int textPosition = 24, bool isBold = false, int fontSize = 10, string fontColor = "000000", bool isItalic = false)
{
var para = new CT_P();
//设置单元格文本对齐
para.AddNewPPr().AddNewTextAlignment();
XWPFParagraph paragraph = new XWPFParagraph(para, table.Body);//创建表格中的段落对象
paragraph.Alignment = paragraphAlign;//文字显示位置,段落排列(左对齐,居中,右对齐)
//paragraph.FontAlignment =Convert.ToInt32(ParagraphAlignment.CENTER);//字体在单元格内显示位置与 paragraph.Alignment效果相似
XWPFRun xwpfRun = paragraph.CreateRun();//创建段落文本对象
xwpfRun.SetText(fillContent);
xwpfRun.FontSize = fontSize;//字体大小
xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
xwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
xwpfRun.IsBold = isBold;//是否加粗
xwpfRun.SetFontFamily("宋体", FontCharRange.None);//设置字体(如:微软雅黑,华文楷体,宋体)
return paragraph;
}
}
}
测试调用
static void Main(string[] args)
{
try
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Name", Type.GetType("System.String")));
dt.Columns.Add(new DataColumn("Age", Type.GetType("System.Int32")));
dt.Columns.Add(new DataColumn("Score", Type.GetType("System.Decimal")));
dt.Columns.Add(new DataColumn("CreateTime", Type.GetType("System.DateTime")));
dt.Columns.Add(new DataColumn("cloum1", Type.GetType("System.Int32")));
dt.Columns.Add(new DataColumn("cloum2", Type.GetType("System.Int32")));
dt.Columns.Add(new DataColumn("cloum3", Type.GetType("System.Int32")));
DataRow dr = dt.NewRow();
dr["Name"] = "张三";
dr["Age"] = 28;
dr["Score"] = 85.5;
dr["CreateTime"] = DateTime.Now;
dr["cloum1"] = 1;
dr["cloum2"] =2;
dr["cloum3"] = 3;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Name"] = "李四";
dr["Age"] = 24;
dr["Score"] = 72;
dr["CreateTime"] = DateTime.Now;
dr["cloum1"] = 1;
dr["cloum2"] = 2;
dr["cloum3"] = 3;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Name"] = "王五";
dr["Age"] = 36;
dr["Score"] = 63.5;
dr["CreateTime"] = DateTime.Now;
dr["cloum1"] = 1;
dr["cloum2"] = 2;
dr["cloum3"] = 3;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["Name"] = "合计";
dr["Age"] = 100;
dr["Score"] = 100;
dt.Rows.Add(dr);
string checkTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
JObject head = new JObject();
head["入库单号"] = "DPT-20200707-0000012";
head["创建日期"] = checkTime;
head["操作员"] = "哈哈";
JObject foot = new JObject();
foot["入库用户"] = "喜喜";
foot["签名"] = "";
SaveWorld.Show("入库单","",head,dt,foot,2);
}
catch (Exception ex)
{
throw ex;
}
}
生成效果
参考文章
https://www.cnblogs.com/Can-daydayup/p/11588531.html @追逐时光者
等其它一些优秀文章,不好之处请见谅,错误之处请大佬们指出。
word合并区域还存在问题,希望有人能帮忙指导一下
亲测可用!!!