• 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、原本样子以及要实现的效果

  • 相关阅读:
    消息队列 RPC之间的区别与联系
    RabbitMQ, ZeroMQ, Kafka 是一个层级的东西吗, 相互之间有哪些优缺点?
    嵌入式软件开发工程师谈软件架构的设计
    值得推荐的C/C++框架和库 (真的很强大)
    10.2-嵌入式系统库资源集合
    正则表达式
    vscode代码阅读
    vscode配置
    VSCode的开发环境zsESampleLinux
    MySQL与宿主Linux之间交互式执行命令
  • 原文地址:https://www.cnblogs.com/fger/p/11187954.html
Copyright © 2020-2023  润新知