NPOI-使用word模板
/// <summary> /// 1、支持定义模板变量的开头与结尾字符 /// 2、支持自定义模板变量查找正则表达式 /// 3、模板中的变量组成"变量开头_变量名称",如:txt_name,变量名称与class中的字段或属性一致 /// 4、支持定义模板中图片变量开头 /// 5、支持定义模板中文本变量中的开头 /// 6、表格不支持处理图片,文本变量命名格式与4相同 /// 7、NPOI BUG提示: /// 使用模板时,定义变量请使用记事本编写后,复制到word中 /// 直接在word中写时,使用 XWPFParagraph.Runs 获取变量可能导致被拆分,如 <name> 被拆成 <,name,>,正确的应该是 ,<name>, /// </summary> public class WordManage { // 模板开头 public string modelStart = "<$"; // 模板结束 public string modelEnd = "$>"; // 模板查找正则表达式 public string regexStr = @"<\$\w+\$>"; // 定义模板中,图片得开头 public string modelPictureStart = "pic_"; // 定义模板中,文字得开头 public string modelTextStart = "txt_"; /// <summary> /// 通过模板创建word文档 /// </summary> public MemoryStream ModelCreateWord<T>(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; } } /// <summary> /// 保存word文档 /// </summary> /// <param name="ms">MemoryStream流对象</param> /// <param name="savepath">保存地址</param> 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<T>(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<string> 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<T>(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<string> matchTexts = GetModelName(text); List<string> paths = new List<string>(); foreach (string str in matchTexts) { // 只处理图片 if (str.IndexOf(modelPictureStart) == -1) { continue; } text = text.Replace(modelStart + str + modelEnd, ""); string name = str.Replace(modelPictureStart, ""); List<string> tempPaths = t.GetValue(name) as List<string>; // 图片不是列表时,尝试解析为字符串 if(tempPaths == null) { string path = t.GetValue(name) as string; if (string.IsNullOrEmpty(path)) { tempPaths = new List<string>() { 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<string> 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<T>(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<CT_P> list_p = item.GetPList(); foreach (var p in list_p) { CT_P addP = addTc.AddNewP(); addP.pPr = p.pPr;//段落样式 IList<CT_R> list_r = p.GetRList(); foreach (CT_R r in list_r) { CT_R addR = addP.AddNewR(); addR.rPr = r.rPr;//run样式 包括字体等 List<CT_Text> 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<string> 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 /// <summary> /// 获取段落中的模板参数 /// </summary> private List<string> GetModelName(string text) { try { List<string> matchTexts = new List<string>(); 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; } } /// <summary> /// 16位guid /// </summary> 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<DataTable> _Tables = new List<DataTable>(); public List<DataTable> Tables { get { return _Tables; } set { _Tables = value; } } /// <summary> /// 获取属性的值,可重写 /// </summary> /// <param name="propertyName">属性名称</param> /// <returns></returns> 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<string> { @"E:\test project\WebApplication10\WebApplication10\Content\timg.jpg" }, text = "zsw", Tables = new List<DataTable>() { 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()); } }
类
/// <summary> /// 未继承AbstractGetValue无法被WordManage使用 /// </summary> public class test : AbstractGetValue { public string text = string.Empty; public List<string> picture = new List<string>(); }
岁月无情催人老,请珍爱生命,远离代码!!!