Net5使用NPOI创建World模板

发布时间 2023-11-05 00:44:31作者: peng_boke

前言

最近需要集成上上签,完成类似在线签约合同的需求,需要传入附件,本来一开始想创建PDF的,但是有很多限制,而且没有找到成熟的方案,项目框架也是Net5,受制于框架,就想到了NPOI。

1.NPOI

1.1Nuget

NPOI支持还蛮多的

image-20230909112613968

项目直接引用,版本根据自己的项目框架决定

第一种方式:
NET CLi 
dotnet add package NPOI --version 2.6.2-rc1
第二种方式:
PM> NuGet\Install-Package NPOI -Version 2.6.2-rc1

image-20230909112728546

2.World模板

这个模板可以根据接口返回的数据自动填充的

可以写一个返回测试数据的JSON串的方法,方便后面测试遍历

image-20230909113632806

3.创建标题

首先创建一个XWPFDocument,设置它的大小为A4

 XWPFDocument document = new XWPFDocument();
 CT_SectPr cT_SectPr = new CT_SectPr();
 //页面大小
 //A4(纵向):W=11906 H=16838
 //A4(横向):W = 16838 H = 11906
 //A5 : W = 8390 H = 11906
 //A6 : W = 5953 H = 8390
 cT_SectPr.pgSz.h = (ulong)16838;
 cT_SectPr.pgSz.w = (ulong)11906;
 ////页面边距
 //cT_SectPr.pgMar.left = (ulong)10;//左边距
 //cT_SectPr.pgMar.right = (ulong)10;//右边距
 //cT_SectPr.pgMar.top = (ulong)10;//上边距
 //cT_SectPr.pgMar.bottom = (ulong)10;//下边距
 document.Document.body.sectPr = cT_SectPr;
 document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, "这是标题", true, 12, "微软雅黑", ParagraphAlignment.CENTER), 0);

ParagraphInstanceSetting方法

先创建一个段落对象,在创建一个段落文本对象,这个方法支持俩个段落文本对象,也可以自己扩展

/// <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;
}

4.创建段落对象和文本对象

第二行创建了一个段落对象,但是创建了6个文本对象,因为有三个是动态的且不需要加粗的

image-20230909171423243

分开创建文本对象的代码:

 XWPFParagraph paragraph = document.CreateParagraph();//创建段落对象
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "期间:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "第一个参数", false, 10, "微软雅黑", ParagraphAlignment.LEFT);
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "     客户联系人:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "第二个参数", false, 10, "微软雅黑", ParagraphAlignment.LEFT);
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "     客户联系电话:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
 NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "第三个参数", false, 10, "微软雅黑", ParagraphAlignment.LEFT);

公共代码:

/// <summary>
/// 创建word文档中的段落对象和设置段落文本的基本样式(字体大小,字体,字体颜色,字体对齐位置)
/// </summary>
/// <param name="paragraph">document文档对象</param>
/// <param name="fillContent">段落第一个文本对象填充的内容</param>
/// <param name="isBold">是否加粗</param>
/// <param name="fontSize">字体大小</param>
/// <param name="fontFamily">字体</param>
/// <param name="paragraphAlign">段落排列(左对齐,居中,右对齐)</param>
/// <param name="fontColor">字体颜色--十六进制</param>
/// <param name="isItalic">是否设置斜体(字体倾斜)</param>
public void ParagraphInstanceSettingExtend(XWPFParagraph paragraph, string fillContent, bool isBold, int fontSize, string fontFamily, ParagraphAlignment paragraphAlign,  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); //设置标题样式如:(微软雅黑,隶书,楷体)根据自己的需求而定       
}

5.创建表格

5.1创建表格 设置列宽

设置表格水平居中,需要用到CT_Tbl。

我一开始设置列宽不好使,最后查阅资料需要用到CT_TblLayoutType。

tblLayout 这个属性 默认值是 autofit 这里需要设置为 fixed 将自动改为固定宽

table.GetCTTbl().AddNewTblPr().tblLayout = new CT_TblLayoutType() { type = ST_TblLayoutType.@fixed };

如果NPOI版本过低,没有GetCTTbl ,可以通过反射。

var tableType = table.GetType();
FieldInfo fieldInfo = tableType.GetField("ctTbl", BindingFlags.NonPublic | BindingFlags.Instance);

表格标题的背景色只能每个单元格的设置,没找到其他一次设置的方法。

然后就是设置标题加粗。

image-20230909171648702

表格代码:

// 第三行:数据表格
var rows = jsonData["Detail"].Count() + 1;
XWPFTable dataXwpfTable = document.CreateTable(rows, 5);//显示的行列数rows行,cols:5列
// 表格水平居中
CT_Tbl cT_Tbl = document.Document.body.getTblArray()[0];
cT_Tbl.AddNewTblPr().jc = new CT_Jc
{
    val = ST_Jc.center
};
// 列宽
dataXwpfTable.GetCTTbl().AddNewTblPr().tblLayout = new CT_TblLayoutType() { type = ST_TblLayoutType.@fixed };
dataXwpfTable.Width = 6500;
dataXwpfTable.SetColumnWidth(0, 1200); /* 设置列宽 */
dataXwpfTable.SetColumnWidth(1, 2300); /* 设置列宽 */
dataXwpfTable.SetColumnWidth(2, 1000); /* 设置列宽 */
dataXwpfTable.SetColumnWidth(3, 1000); /* 设置列宽 */
dataXwpfTable.SetColumnWidth(4, 1000); /* 设置列宽 */
// 表格标题背景色
var colArr = new List<short> { 0, 1, 2, 3, 4 };
colArr.ForEach(colIndex => { dataXwpfTable.GetRow(0).GetCell(colIndex).SetColor("DDEBF7"); });
// 表格标题
dataXwpfTable.GetRow(0).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, $"日期", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
dataXwpfTable.GetRow(0).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "摘要", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
dataXwpfTable.GetRow(0).GetCell(2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "货款金额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
dataXwpfTable.GetRow(0).GetCell(3).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "收款金额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
dataXwpfTable.GetRow(0).GetCell(4).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "余额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
int rowIndex = 1;

公共方法:

/// <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, string fontFamily, 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效果相似
    paragraph.VerticalAlignment = TextAlignment.CENTER;
    paragraph.SpacingAfterLines = textPosition;//下方距离
    paragraph.SpacingBeforeLines = textPosition;//上方距离
    //paragraph.FillBackgroundColor = backColor; // "DDEBF7";
    //设置文本高度(行间距)
    //paragraph.TextPosition = 120;
    XWPFRun xwpfRun = paragraph.CreateRun();//创建段落文本对象
    xwpfRun.SetText(fillContent);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
    xwpfRun.FontSize = fontSize;//字体大小
    xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
    xwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
    xwpfRun.IsBold = isBold;//是否加粗
    xwpfRun.SetFontFamily(fontFamily, FontCharRange.None);//设置字体(如:微软雅黑,华文楷体,宋体)
    //xwpfRun.SetTextPosition(textPosition);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
    //xwpfRun.GetCTR().AddNewRPr().AddNewShd().fill = backColor;
    return paragraph;
}

5.2动态添加表体

我这里测试数据传的是JObject,可以通过[]获取值

image-20230909172608307

表格代码,公共方法和5.1一样,后面会全部贴出

int rowIndex = 1;
foreach (var data in jsonData["Detail"])
{
    if (!data["ViewDate"].ToString().Contains("本期欠款金额"))
    {
        dataXwpfTable.GetRow(rowIndex).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["ViewDate"].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
        dataXwpfTable.GetRow(rowIndex).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["Abstract"].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
        decimal.TryParse(data["DebitAmount"].ToString(), out decimal debitAmount);
        dataXwpfTable.GetRow(rowIndex).GetCell(2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", debitAmount).Replace("¥", ""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
        decimal.TryParse(data["CreditAmount"].ToString(), out decimal creditAmount);
        dataXwpfTable.GetRow(rowIndex).GetCell(3).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", creditAmount).Replace("¥", ""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
        decimal.TryParse(data["DebitTotalAmount"].ToString(), out decimal debitTotalAmount);
        dataXwpfTable.GetRow(rowIndex).GetCell(4).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", debitTotalAmount).Replace("¥", ""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
    }
    else
    {
        dataXwpfTable.GetRow(rowIndex).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["ViewDate"].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
        dataXwpfTable.GetRow(rowIndex).MergeCells(1, 4);//合并4列
        dataXwpfTable.GetRow(rowIndex).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["Abstract"].ToString(), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
    }
    rowIndex++;
}

6.创建完成

本来写的是API接口,为了避坑,先写了个控制台程序

string dire = System.AppDomain.CurrentDomain.BaseDirectory + "Files";
// 判断目录是否存在,不存在则创建
if (!Directory.Exists(dire))
{
    Directory.CreateDirectory(dire);
}
// 文件保存
using (var stream = new FileStream(Path.Combine(dire, "测试" + DateTime.UtcNow.Ticks.ToString() + ".docx"), FileMode.Create))
{
    document.Write(stream);
}
document.Close();
document.Dispose();

Console.WriteLine("生成完成");

7.完整代码

NPOI公共代码

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, textPosition);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
        xwpfRun.FontSize = fontSize;//字体大小
        xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
        xwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
        xwpfRun.IsBold = isBold;//是否加粗
        xwpfRun.SetFontFamily("宋体", FontCharRange.None);//设置字体(如:微软雅黑,华文楷体,宋体)
        //xwpfRun.SetTextPosition(textPosition);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
        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, string fontFamily, 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效果相似
        paragraph.VerticalAlignment = TextAlignment.CENTER;
        paragraph.SpacingAfterLines = textPosition;//下方距离
        paragraph.SpacingBeforeLines = textPosition;//上方距离
        //paragraph.FillBackgroundColor = backColor; // "DDEBF7";
        //设置文本高度(行间距)
        //paragraph.TextPosition = 120;
        XWPFRun xwpfRun = paragraph.CreateRun();//创建段落文本对象
        xwpfRun.SetText(fillContent);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
        xwpfRun.FontSize = fontSize;//字体大小
        xwpfRun.SetColor(fontColor);//设置字体颜色--十六进制
        xwpfRun.IsItalic = isItalic;//是否设置斜体(字体倾斜)
        xwpfRun.IsBold = isBold;//是否加粗
        xwpfRun.SetFontFamily(fontFamily, FontCharRange.None);//设置字体(如:微软雅黑,华文楷体,宋体)
        //xwpfRun.SetTextPosition(textPosition);//设置文本位置(设置两行之间的行间),从而实现table的高度设置效果 
        //xwpfRun.GetCTR().AddNewRPr().AddNewShd().fill = backColor;
        return paragraph;
    }


    /// <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 void ParagraphInstanceSettingExtend(XWPFParagraph paragraph, string fillContent, bool isBold, int fontSize, string fontFamily, ParagraphAlignment paragraphAlign, bool isStatement = false,  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); //设置标题样式如:(微软雅黑,隶书,楷体)根据自己的需求而定       
    }
}

表格代码(出于安全考虑我把测试json串给删掉了,自己添加测试的json数据就行了):

static void Main(string[] args)
{
    XWPFDocument document = new XWPFDocument();

    CT_SectPr cT_SectPr = new CT_SectPr();
    //页面大小
    //A4(纵向):W=11906 H=16838
    //A4(横向):W = 16838 H = 11906
    //A5 : W = 8390 H = 11906
    //A6 : W = 5953 H = 8390
    cT_SectPr.pgSz.h = (ulong)16838;
    cT_SectPr.pgSz.w = (ulong)11906;
    ////页面边距
    //cT_SectPr.pgMar.left = (ulong)10;//左边距
    //cT_SectPr.pgMar.right = (ulong)10;//右边距
    //cT_SectPr.pgMar.top = (ulong)10;//上边距
    //cT_SectPr.pgMar.bottom = (ulong)10;//下边距
    document.Document.body.sectPr = cT_SectPr;
    
    document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, "对账明细", true, 12, "微软雅黑", ParagraphAlignment.CENTER), 0);

    XWPFParagraph paragraph = document.CreateParagraph();//创建段落对象
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "期间:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "2022-12-01~2023-05-26", false, 10, "微软雅黑", ParagraphAlignment.LEFT);
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "     客户联系人:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "何杰", false, 10, "微软雅黑", ParagraphAlignment.LEFT);
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "     客户联系电话:", true, 10, "微软雅黑", ParagraphAlignment.LEFT);
    NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSettingExtend(paragraph, "010-60279999", false, 10, "微软雅黑", ParagraphAlignment.LEFT);

    var jsonData = getJsonData();
    // 数据表格
    var rows = jsonData["Detail"].Count() + 1;
    XWPFTable dataXwpfTable = document.CreateTable(rows, 5);//显示的行列数rows:5行,cols:7列
    
    // 表格水平居中
    CT_Tbl cT_Tbl = document.Document.body.getTblArray()[0];
    cT_Tbl.AddNewTblPr().jc = new CT_Jc();
    cT_Tbl.AddNewTblPr().jc.val = ST_Jc.center;

    // 列宽
    dataXwpfTable.GetCTTbl().AddNewTblPr().tblLayout = new CT_TblLayoutType() { type = ST_TblLayoutType.@fixed };
    dataXwpfTable.Width = 6500;
    dataXwpfTable.SetColumnWidth(0, 1200); /* 设置列宽 */
    dataXwpfTable.SetColumnWidth(1, 2300); /* 设置列宽 */
    dataXwpfTable.SetColumnWidth(2, 1000); /* 设置列宽 */
    dataXwpfTable.SetColumnWidth(3, 1000); /* 设置列宽 */
    dataXwpfTable.SetColumnWidth(4, 1000); /* 设置列宽 */

    // 第一行背景色
    dataXwpfTable.GetRow(0).GetCell(0).SetColor("DDEBF7");
    dataXwpfTable.GetRow(0).GetCell(1).SetColor("DDEBF7");
    dataXwpfTable.GetRow(0).GetCell(2).SetColor("DDEBF7");
    dataXwpfTable.GetRow(0).GetCell(3).SetColor("DDEBF7");
    dataXwpfTable.GetRow(0).GetCell(4).SetColor("DDEBF7");
    dataXwpfTable.GetRow(0).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, $"日期", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
    dataXwpfTable.GetRow(0).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "摘要", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
    dataXwpfTable.GetRow(0).GetCell(2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "货款金额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
    dataXwpfTable.GetRow(0).GetCell(3).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "收款金额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));
    dataXwpfTable.GetRow(0).GetCell(4).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, "余额", ParagraphAlignment.CENTER, "微软雅黑", 25, true, 10));



    int rowIndex = 1;
    foreach (var data in jsonData["Detail"])
    {
        if (!data["ViewDate"].ToString().Contains("本期欠款金额"))
        {                
            dataXwpfTable.GetRow(rowIndex).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data[""].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
            dataXwpfTable.GetRow(rowIndex).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data[""].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
            decimal.TryParse(data[""].ToString(),out decimal debitAmount);
            dataXwpfTable.GetRow(rowIndex).GetCell(2).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", debitAmount).Replace("¥", ""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
            decimal.TryParse(data[""].ToString(), out decimal creditAmount);
            dataXwpfTable.GetRow(rowIndex).GetCell(3).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", creditAmount).Replace("¥",""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
            decimal.TryParse(data[""].ToString(), out decimal debitTotalAmount);
            dataXwpfTable.GetRow(rowIndex).GetCell(4).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, string.Format("{0:C}", ).Replace("¥", ""), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
        }
        else
        {
            dataXwpfTable.GetRow(rowIndex).GetCell(0).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["ViewDate"].ToString(), ParagraphAlignment.LEFT, "微软雅黑", 25, false, 10));
            dataXwpfTable.GetRow(rowIndex).MergeCells(1, 4);//合并4列
            dataXwpfTable.GetRow(rowIndex).GetCell(1).SetParagraph(NpoiWordParagraphTextStyleHelper._.SetTableParagraphInstanceSetting(document, dataXwpfTable, data["Abstract"].ToString(), ParagraphAlignment.RIGHT, "微软雅黑", 25, false, 10));
        }
        rowIndex++;
    }

    string dire = System.AppDomain.CurrentDomain.BaseDirectory + "Files";
    // 判断目录是否存在,不存在则创建
    if (!Directory.Exists(dire))
    {
        Directory.CreateDirectory(dire);
    }

    // 文件保存
    using (var stream = new FileStream(Path.Combine(dire, "测试" + DateTime.UtcNow.Ticks.ToString() + ".docx"), FileMode.Create))
    {
        document.Write(stream);
    }

    document.Close();
    document.Dispose();

    Console.WriteLine("生成完成");
}



static JObject getJsonData()
{
    string jsonstr = "";
    return JObject.Parse(jsonstr);
}

8.API接口

如果想使用API接口调用,改一下返回参数即可

8.1后端

创建完成后写入Stream,可以转换成byte,也可不转换,通过File对象,支持byte[]和Stream

using MemoryStream stream = new();
document.Write(stream);
byte[] bytes = stream.ToArray();
document.Close();
document.Dispose();
return await Task.FromResult<byte[]>(bytes);

自己的测试数据传进去生成world,返回File。

AllowAnonymous设置不需要权限,负责前端调用就需要传token。

Controller:

[HttpGet]
[Route("bbb/CreateWorld/{key}")]
[AllowAnonymous]
public async Task<FileResult> CreateWrold([FromServices] Provider provider, string key)
{
    var xxx = provider.GetDetail(key.ToLong());
    var bytes = await _xxxProvider.CreateWrold(JObject.FromObject(xxx));
    return File(bytes, "application/octet-stream", "测试.docx");
}

8.2前端

创建a标签,实现调用

downloadfile() {
         // world
         let date = new Date();
         //const fileName = '测试.docx';
         const link = document.createElement('a'); // 创建a标签
         //link.download = fileName; // a标签添加属性
         link.style.display = 'none';
         link.href =`http://localhost:9008/api/aaa/bbb/CreateWorld/${this.data.id}`;
         document.body.appendChild(link);
         link.click(); // 执行下载
         URL.revokeObjectURL(link.href); // 释放url
         document.body.removeChild(link); // 释放标签
    }

9.总结

前前后后做了俩三天,查看了很多资料,遇到了很多问题,也算顺利,总结一下,希望帮助大家。

10.参考

.NET Core使用NPOI导出复杂Word详解:

https://www.cnblogs.com/Can-daydayup/p/11588531.html

.NET Core使用NPOI导出复杂Word详解

https://www.cnblogs.com/Can-daydayup/p/11588531.html

.NET Core使用NPOI将Excel中的数据批量导入到MySQL

https://www.cnblogs.com/Can-daydayup/p/12593165.html

NPOI关于 WORD 中 TABLE 的列宽设置

https://www.cnblogs.com/lixi12138/p/15090179.html

Word文档导出之NPOI (.Net core6.0)

https://www.cnblogs.com/ZhuMeng-Chao/p/17074271.html

创作不易,如果感觉帮助到你了,还请多多支持,我会继续努力。

image-20230909175602009