NPOI-使用word模板


/// 
    /// 1、支持定义模板变量的开头与结尾字符
    /// 2、支持自定义模板变量查找正则表达式
    /// 3、模板中的变量组成"变量开头_变量名称",如:txt_name,变量名称与class中的字段或属性一致
    /// 4、支持定义模板中图片变量开头
    /// 5、支持定义模板中文本变量中的开头
    /// 6、表格不支持处理图片,文本变量命名格式与4相同
    /// 7、NPOI BUG提示:
    ///     使用模板时,定义变量请使用记事本编写后,复制到word中
    ///     直接在word中写时,使用  XWPFParagraph.Runs 获取变量可能导致被拆分,如  被拆成 <,name,>,正确的应该是  ,,
    /// 
    public class WordManage
    {
        // 模板开头
        public string modelStart = "<$";
        // 模板结束
        public string modelEnd = "$>";
        // 模板查找正则表达式
        public string regexStr = @"<\$\w+\$>";
        // 定义模板中,图片得开头
        public string modelPictureStart = "pic_";
        // 定义模板中,文字得开头
        public string modelTextStart = "txt_";

        /// 
        /// 通过模板创建word文档
        /// 
        public MemoryStream ModelCreateWord(string filepath, T t) where T : AbstractGetValue
        {
            using (FileStream stream = File.OpenRead(filepath))
            {
                XWPFDocument doc = new XWPFDocument(stream);
                
                // 遍历段落                  
                foreach (var para in doc.Paragraphs)
                {
                    ReplaceText(para, t);
                    ReplacePictures(para, t);
                }

                // 处理表格
                ReplaceTables(doc,t); 

                // 写入流
                MemoryStream ms = new MemoryStream();
                doc.Write(ms);
                return ms;
            }
        }

        /// 
        /// 保存word文档
        /// 
        /// MemoryStream流对象
        /// 保存地址
        public void SaveWord(MemoryStream ms,string savepath)
        {
            try
            {
                FileStream fs = new FileStream(savepath, FileMode.OpenOrCreate);
                BinaryWriter w = new BinaryWriter(fs);
                w.Write(ms.ToArray());
                fs.Close();
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

        #region 模板字符替换

        private void ReplaceText(XWPFParagraph para, T t) where T : AbstractGetValue
        {
            if (para == null)
            {
                throw new Exception("XWPFParagraph对象引用为null");
            }

            if (t == null)
            {
                throw new Exception(t.GetType().Name + "对象引用为null");
            }

            try
            {
                string text = para.ParagraphText;

                List matchTexts = GetModelName(text);

                foreach (string str in matchTexts)
                {
                    if (str.IndexOf(modelTextStart) > -1)
                    {
                        string name = str.Replace(modelTextStart, "");
                        string newText = Convert.ToString(t.GetValue(name));

                        para.ReplaceText(modelStart + str + modelEnd, newText);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion 

        #region 模板图片插入

        private void ReplacePictures(XWPFParagraph para, T t) where T : AbstractGetValue
        {
            if (para == null)
            {
                throw new Exception("XWPFParagraph对象引用为null");
            }

            if (t == null)
            {
                return;
            }

            // 段落中得文本对象
            var runs = para.Runs;

            try
            {
                for (int i = 0; i < runs.Count; i++)
                {
                    var run = runs[i];
                    string text = run.ToString();

                    List matchTexts = GetModelName(text);

                    List paths = new List();

                    foreach (string str in matchTexts)
                    {
                        // 只处理图片
                        if (str.IndexOf(modelPictureStart) == -1)
                        {
                            continue;
                        }

                        text = text.Replace(modelStart + str + modelEnd, "");

                        string name = str.Replace(modelPictureStart, "");

                        List tempPaths = t.GetValue(name) as List;

                        // 图片不是列表时,尝试解析为字符串
                        if(tempPaths == null)
                        {
                            string path = t.GetValue(name) as string;

                            if (string.IsNullOrEmpty(path))
                            {
                                tempPaths = new List()
                                {
                                    path
                                };
                            }
                        }

                        if (tempPaths != null && tempPaths.Count > 0)
                        {
                            paths.AddRange(tempPaths);
                        }
                    }

                    run.SetText(text, 0);

                    ReplacePictures(run, paths);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void ReplacePictures(XWPFRun run, List paths)
        {
            if (run == null)
            {
                throw new Exception("XWPFRun对象引用为null");
            }

            try
            {
                foreach (string path in paths)
                {
                    if (string.IsNullOrEmpty(path))
                    {
                        continue;
                    }

                    Bitmap b = new Bitmap(path);
                    FileStream gfs = new FileStream(path, FileMode.Open, FileAccess.Read);

                    int width = b.Width;
                    int height = b.Height;
                    double fold = 1;

                    if (width > 600)
                    {
                        fold = width / 600.0;
                    }

                    width = Convert.ToInt32(width / fold);
                    height = Convert.ToInt32(height / fold);

                    // 获取后缀
                    string extension = Path.GetExtension(path);
                    // 随机名称
                    string name = GuidTo16String() + extension;

                    // 添加图片到文档中
                    run.AddPicture(gfs, (int)PictureType.JPEG, name, Units.PixelToEMU(width), Units.PixelToEMU(height));
                    
                    b.Dispose();
                    gfs.Close();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 表格

        public void ReplaceTables(XWPFDocument doc,T t) where T:AbstractGetValue
        {
            try
            {
                if (doc == null)
                {
                    throw new Exception("XWPFDocument对象引用为null");
                }

                if (t.Tables == null || t.Tables.Count == 0)
                {
                    return;
                }

                var tables = doc.Tables;

                // 无模板
                if (tables.Count == 0)
                {
                    return;
                }

                for (int i = 0; i < t.Tables.Count; i++)
                {
                    if (t.Tables[i] == null || t.Tables[i].Rows.Count == 0)
                    {
                        continue;
                    }

                    XWPFTable table = tables[i];

                    if (table != null)
                    {
                        ReplaceTable(table, t.Tables[i]);
                    }
                }
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

        private void ReplaceTable(XWPFTable table, DataTable dataTable)
        {
            try
            {
                XWPFTableRow modelRows = table.Rows[1];
                CT_Row ctrow = modelRows.GetCTRow();

                table.RemoveRow(table.Rows.IndexOf(modelRows)); //先移除模板行

                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    //复制cell结构
                    CT_Row targetRow = new CT_Row();

                    foreach (CT_Tc item in ctrow.Items)
                    {
                        CT_Tc addTc = targetRow.AddNewTc();
                        addTc.tcPr = item.tcPr;//cell样式,只包括列宽和cell对齐方式

                        IList list_p = item.GetPList();

                        foreach (var p in list_p)
                        {
                            CT_P addP = addTc.AddNewP();
                            addP.pPr = p.pPr;//段落样式
                            IList list_r = p.GetRList();
                            foreach (CT_R r in list_r)
                            {
                                CT_R addR = addP.AddNewR();
                                addR.rPr = r.rPr;//run样式 包括字体等
                                List list_text = r.GetTList();
                                foreach (CT_Text text in list_text)
                                {
                                    CT_Text addText = addR.AddNewT();
                                    addText.space = text.space;
                                    addText.Value = text.Value;
                                }
                            }
                        }
                    }

                    XWPFTableRow mrow = new XWPFTableRow(targetRow, table);
                    table.AddRow(mrow);

                    // 填数据 第一行标题,数据填充从第二行开始
                    foreach (var cells in table.Rows[i + 1].GetTableCells())
                    {
                        foreach (var para in cells.Paragraphs)
                        {
                            List texts = GetModelName(para.ParagraphText);

                            foreach (string str in texts)
                            {
                                if (str.IndexOf(modelTextStart) > -1)
                                {
                                    string name = str.Replace(modelTextStart, "");
                                    string newText = Convert.ToString(dataTable.Rows[i][name]);
                                    para.ReplaceText(modelStart + str + modelEnd, newText);
                                }
                            }
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

        #endregion 

        /// 
        /// 获取段落中的模板参数
        /// 
        private List GetModelName(string text)
        {
            try
            {
                List matchTexts = new List();

                Regex reg = new Regex(regexStr);
                Match match = reg.Match(text);

                bool result = match.Success;

                while (result)
                {
                    string matchText = match.Groups[0].Value.Replace(modelStart, "").Replace(modelEnd, "");
                    matchTexts.Add(matchText);

                    match = match.NextMatch();
                    result = match.Success;
                }

                return matchTexts;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        /// 
        /// 16位guid
        /// 
        private string GuidTo16String()
        {
            long i = 1;
            foreach (byte b in Guid.NewGuid().ToByteArray())
            {
                i *= ((int)b + 1);
            }
            return string.Format("{0:x}", i - DateTime.Now.Ticks);
        }
    }

  可供WordManage使用的类必须继承AbstractGetValue

public class AbstractGetValue
    {
        private List _Tables = new List();

        public List Tables
        {
            get { return _Tables; }
            set { _Tables = value; }
        }

        /// 
        /// 获取属性的值,可重写
        /// 
        /// 属性名称
        /// 
        public virtual object GetValue(string propertyName)
        {
            PropertyInfo property = this.GetType().GetProperty(propertyName);

            if (property == null)
            {
                FieldInfo field = this.GetType().GetField(propertyName);

                if (field != null)
                {
                    return field.GetValue(this);
                }

                return string.Empty;
            }
            else
            {
                return property.GetValue(this);
            }
        }
    }

  使用

 public void CreateWord()
        {
            // 模板地址
            string filepath = Server.MapPath("~/Content/FileModal/Word/demo.docx");

            // word生成
            WordManage word = new WordManage();

            #region 添加表格数据
            DataTable dt = new DataTable();

            dt.Columns.Add("column1");
            dt.Columns.Add("column2");
            dt.Columns.Add("column3");
            dt.Columns.Add("column4");

            DataRow newRow = dt.NewRow();
            newRow["column1"] = "zsw";
            newRow["column2"] = "13800000000";
            newRow["column3"] = "430723199005042222";
            newRow["column4"] = "读书";

            dt.Rows.Add(newRow);

            newRow = dt.NewRow();
            newRow["column1"] = "lisi";
            newRow["column2"] = "15555555555";
            newRow["column3"] = "446885222111256654";
            newRow["column4"] = "游泳";

            dt.Rows.Add(newRow);

            test t = new test()
            {
                picture = new List { @"E:\test project\WebApplication10\WebApplication10\Content\timg.jpg" },
                text = "zsw",
                Tables = new List() { dt }
            };

            #endregion

            // 流未关闭,请使用using或者ms.Close()
            using (MemoryStream ms = word.ModelCreateWord(filepath, t))
            {
                // 保存路径
                string path = @"E:\test project\WebApplication10\WebApplication10\Content\timg.docx";
                word.SaveWord(ms, path);

                // 生成成功后,需要保存网络路径到数据库

                // 保存完成后,直接下载,请保持docx的编码格式
                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.BinaryWrite(ms.ToArray());
            }
        }
/// 
    /// 未继承AbstractGetValue无法被WordManage使用
    /// 
    public class test : AbstractGetValue
    {
        public string text = string.Empty;
        public List picture = new List();
    }