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>();
}
岁月无情催人老,请珍爱生命,远离代码!!!

浙公网安备 33010602011771号