项目开发过程当中,咱们要把数据以各类各样的形式展示给客户。把数据以文档的形式展示给客户相信是一种比较头疼的问题,若是没有好的方法会html
使得个人开发繁琐,并且知足不了客户的需求。接下来我会经过两种开发方式介绍如何将数据输出到Word 文档上。我会分两篇文章介绍,第一篇前端
介绍不使用插件的状况下操做word,第二篇文章将介绍一种强大的插件操做word。下面开始第一篇文章。[本次实例源代码从这里下载]后端
文章梗概:服务器
♦ 不使用模板将数据输出到 wordapp
♦ 输出数据到 word 在后端设置输出内容ide
♦ 输出数据到 word 在前端设置输出内容post
♦ 经过把word另存为html 文件的形式作成模板输出到word字体
♦ 经过把word另存为mht 文件的形式作成模板输出到wordui
前端定义两个服务器按钮:
1 <div id="container" style=""> 2 不利用模板:<br /> 3 <br /> 4 <asp:Button ID="CreateWordBehind" runat="server" Text="输出数据到word(后台设置内容)" OnClick="CreateWordBehind_Click" /> 5 <asp:Button ID="CreateWordFront" runat="server" Text="输出数据到word(前台设置内容)" OnClick="CreateWordFront_Click" /> 6 <hr /> 7 </div>
后端代码输出到word,代码很简单只要设置输出头为word,而输出的内容放到 StringBuilder 里,而且经过 StringBuilder实例,去设置要输出的内容,包括字体、颜色....
1 /// <summary> 2 /// 输出数据到word(后台设置内容) 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void CreateWordBehind_Click(object sender, EventArgs e) 7 { 8 HttpContext.Current.Response.Clear(); 9 HttpContext.Current.Response.Buffer = true; 10 HttpContext.Current.Response.Charset = ""; 11 12 // 设置输出头 13 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + System.Web.HttpUtility.UrlEncode("CreateWord", System.Text.Encoding.UTF8) + ".doc"); 14 15 // 设置输出的编码格式 16 HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.Default; 17 18 // Response.ContentType指定文件类型 能够为application/ms-excel || application/ms-word || application/ms-txt || application/ms-html 19 // 由于是输出word 因此这里就指定为 application/ms-word 20 HttpContext.Current.Response.ContentType = "application/ms-word"; 21 22 // 定义StringBuilder 把要输出的内容写到里面,而且能够设置字体、颜色、大小等... 23 StringBuilder sb = new StringBuilder(); 24 sb.AppendLine("<div style='text-align:center;font-size:18px;font-weight:bold;'>导出数据到word</div>"); 25 sb.AppendLine("这是导出到word的数据<br />"); 26 sb.AppendLine("<span style='color:blue;'>这是导出到word的数据</span>"); 27 28 HttpContext.Current.Response.Output.Write(sb); 29 HttpContext.Current.Response.Flush(); 30 HttpContext.Current.Response.End(); 31 }
运行、点击按钮、打开word文档,效果以下:
前端设置输出的html内容。以输出一个表格为例。其中有两个div 标记了runat="server",这样后台就能够取到这个id,用途一会介绍。
1 <div id="WordContent" runat="server"> 2 <div runat="server" id="title">表头</div> 3 <table border="1" style="width:400px;line-height: 25px;"> 4 <tr style="width:400px; height:25px;"> 5 <td> 6 编号 7 </td> 8 <td> 9 姓名 10 </td> 11 <td> 12 成绩 13 </td> 14 </tr> 15 <tr style="width:400px; height:25px;"> 16 <td> 17 </td> 18 <td> 19 </td> 20 <td> 21 </td> 22 </tr> 23 </table> 24 </div>
至此前端的所有代码以下:
1 <form id="form1" runat="server"> 2 <div id="WordContent" runat="server"> 3 <div runat="server" id="title">表头</div> 4 <table border="1" style="width:400px;line-height: 25px;"> 5 <tr style="width:400px; height:25px;"> 6 <td> 7 编号 8 </td> 9 <td> 10 姓名 11 </td> 12 <td> 13 成绩 14 </td> 15 </tr> 16 <tr style="width:400px; height:25px;"> 17 <td> 18 </td> 19 <td> 20 </td> 21 <td> 22 </td> 23 </tr> 24 </table> 25 </div> 26 <div id="container" style=""> 27 不利用模板:<br /> 28 <br /> 29 <asp:Button ID="CreateWordBehind" runat="server" Text="输出数据到word(后台设置内容)" OnClick="CreateWordBehind_Click" /> 30 <asp:Button ID="CreateWordFront" runat="server" Text="输出数据到word(前台设置内容)" OnClick="CreateWordFront_Click" /> 31 <hr /> 32 </div> 33 </form>
后端代码输出到word的代码和就是把以前的StringBuilder 换成了StringWriter,StringWriter的信息其实也是经过Stringbulider存储的。另外加上一个
HtmlTextWriter对象,HtmlTextWriter能够把前端渲染后的页面以流的形式输出。
这是候咱们就能够看出在前端html中标记的id的用途了,这样就能够把id标记为WordContent的里面的内容所有输出到word,而其余的内容也不会输出到word上了。
又因为前端html中id标记了title的div标签在后台设置了title.Style.Add(HtmlTextWriterStyle.Display, "none");因此它也不会被输出到word上。
1 /// <summary> 2 /// 输出数据到word(前台设置内容) 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void CreateWordFront_Click(object sender, EventArgs e) 7 { 8 HttpContext.Current.Response.Clear(); 9 HttpContext.Current.Response.Buffer = true; 10 HttpContext.Current.Response.Charset = ""; 11 12 // 设置输出头 13 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + System.Web.HttpUtility.UrlEncode("CreateWord", System.Text.Encoding.UTF8) + ".doc"); 14 15 // 设置输出的编码格式 16 HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.Default; 17 18 // Response.ContentType指定文件类型 能够为application/ms-excel || application/ms-word || application/ms-txt || application/ms-html 19 // 由于是输出word 因此这里就指定为 application/ms-word 20 HttpContext.Current.Response.ContentType = "application/ms-word"; 21 22 // 定义输出流,其信息也是存储在StringBuilder中的 23 System.IO.StringWriter oStringWriter = new System.IO.StringWriter(); 24 25 // 定义一个服务器控件输出流(能够把前端渲染后的页面以流的形式输出) 26 System.Web.UI.HtmlTextWriter oHtmlTextWriter = new System.Web.UI.HtmlTextWriter(oStringWriter); 27 28 // 控制前端的样式 (HtmlTextWriterStyle 枚举用来控制 显示、字体、大小、颜色...) 29 title.Style.Add(HtmlTextWriterStyle.Display, "none"); 30 31 // 这样会把前端的整个页面输出,因为有些其余元素不须要输出,因此注释 32 //this.RenderControl(oHtmlTextWriter); 33 34 // 指定咱们前端标记要输出的容器,容器包含的内容均可以输出 35 this.WordContent.RenderControl(oHtmlTextWriter); 36 37 HttpContext.Current.Response.Output.Write(oStringWriter); 38 HttpContext.Current.Response.Flush(); 39 HttpContext.Current.Response.End(); 40 }
运行、点击按钮发现报错,提示"只能在执行 Render() 的过程当中调用 RegisterForEventValidation;"这个错误的缘由就是怀疑经过post方法发送恶意的数据,解决方法:
在当前aspx页面头部加上:EnableEventValidation="false",默认为true。
1 <%@ Page Language="C#" AutoEventWireup="true" EnableEventValidation="false" CodeBehind="OperateWord.aspx.cs" 2 Inherits="OperateWordPro.OperateWordDemo1.OperateWord" %>
再运行、点击按钮、打开word,效果以下(固然需求不可能那么简单,具体输出的样式就要在html中慢慢的调整了):
由于若是用前面的方式,将数据都是本身拼接的,包括样式全是本身控制,难度将很是大,而且效果也很让到客户的满意(如:要求页眉、页脚)。因此若是可以程序直接读取word模板把要输出的内容填充进去将会大大的缩短咱们的时间,最主要的是版式不用咱们太关心。
一、 经过把word另存为html 文件的形式作成模板输出到word
把word文档作成模板的思路就是把word文档保存为html程序能够直接读取的形式。因为篇幅的问题,具体把word另存为html的细节能够请参考这篇博文。下面有这样一个结构的word文档须要输出,经过用读取模板的形式咱们只要把下面几个站位符替换掉就能够了(如,要输出名字的地方加上了{name}...),思路很简单。
前台html代码:
1 利用模板输出到word:<br /><br /> 2 <asp:Button ID="CreateWordByHtmlTemplate" runat="server" Text="经过htm模板生成Word" OnClick="CreateWordByHtmlTemplate_Click" /> 3 <asp:Button ID="CreateWordBymhtTemplate" runat="server" Text="经过mht模板生成Word" OnClick="CreateWordBymhtTemplate_Click" />
在项目中添加一个Document文件夹,将模板文件“通知.html”拷贝到这个问价夹下。
下面是后台代码:
1 /// <summary> 2 /// 经过htm模板生成Word 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void CreateWordByHtmlTemplate_Click(object sender, EventArgs e) 7 { 8 // 获取模板的路径 经过ExprotToWord处理返回 字符串 9 string strWord = DealTemplate(Server.MapPath("../Document/通知.html")); 10 11 Response.ContentEncoding = System.Text.Encoding.Default; 12 Response.ClearContent(); 13 Response.ClearHeaders(); 14 Response.AddHeader("content-disposition", "attachment;filename=合同.doc"); //必须的 15 Response.AddHeader("Content-type", "application"); 16 Response.ContentType = "application/ms-html"; 17 Response.ContentEncoding = System.Text.Encoding.Default; 18 19 Response.Write(strWord); 20 Response.Flush(); 21 Response.Close(); 22 } 23 24 /// <summary> 25 /// 处理模板 返回处理结果 26 /// </summary> 27 /// <param name="templatePath"></param> 28 /// <returns></returns> 29 public string DealTemplate(string templatePath) 30 { 31 StringBuilder sb = new StringBuilder(1024); 32 33 // 读取文档内容并转换成流的形式 编码为默认编码 34 StreamReader sr = new StreamReader(templatePath, Encoding.Default); 35 36 // 将流转换成字符串加进StringBuilder中 37 sb.Append(Encoding.Default.GetString(Encoding.Default.GetBytes(sr.ReadToEnd()))); 38 39 // 把文档中咱们设置的标志位换成咱们想要的内容 40 sb.Replace("{name}", "张三"); 41 sb.Replace("{orderNumber}", "ooxx124512"); 42 sb.Replace("{tel}", "1383838383"); 43 44 return sb.ToString(); 45 }
运行、点击按钮、打开word,效果以下
二、 经过把word另存为mht 文件的形式作成模板输出到word
经过把word存储为html的形式解决了大量手工拼接数据和word的基本版式问题,可是若是这个word中含有图片和页眉页脚就没法经过这种方式处理了,由于html存储的是单文件,是和图片这些“其余元素”分开的。因此若是仍是要经过模板的方式解决那么这个模板要含有文字、图片、页眉设置、页脚设置。通过一番测试,发现把word另存为.mht的方式能够解决这个问题。上网查了资料说.mht就是htm和图片等的复合文件。那么咱们继续吧。
制做一个word在上一个word的基础上添加了一个含有图片的word:
把这个word另存为"通知2.mht",并复制到Document文件夹下。
后台代码和上面代码同样,只是换了个模板而已,可是编码格式要作微调,红字部分标注了:
1 /// <summary> 2 /// 经过mht模板生成Word 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void CreateWordBymhtTemplate_Click(object sender, EventArgs e) 7 { 8 // 获取模板的路径 经过ExprotToWord处理返回 字符串 9 string strWord = DealTemplate(Server.MapPath("../Document/通知2.mht")); 10 11 Response.ContentEncoding = System.Text.Encoding.Default; 12 Response.ClearContent(); 13 Response.ClearHeaders(); 14 Response.AddHeader("content-disposition", "attachment;filename=合同.doc"); //必须的 15 Response.AddHeader("Content-type", "application"); 16 Response.ContentType = "application/ms-html"; 17 Response.ContentEncoding = System.Text.Encoding.Default; 18 19 Response.Write(strWord); 20 Response.Flush(); 21 Response.Close(); 22 } 23 24 /// <summary> 25 /// 处理模板 返回处理结果 26 /// </summary> 27 /// <param name="templatePath"></param> 28 /// <returns></returns> 29 public string DealTemplate(string templatePath) 30 { 31 StringBuilder sb = new StringBuilder(1024); 32 33 // 读取文档内容并转换成流的形式 此处编码要设置为UTF8 34 StreamReader sr = new StreamReader(templatePath, Encoding.UTF8); 35 36 // 将流转换成字符串加进StringBuilder中 37 sb.Append(Encoding.Default.GetString(Encoding.Default.GetBytes(sr.ReadToEnd()))); 38 39 // 把文档中咱们设置的标志位换成咱们想要的内容 40 sb.Replace("{name}", "张三"); 41 sb.Replace("{orderNumber}", "ooxx124512"); 42 sb.Replace("{tel}", "1383838383"); 43 44 return sb.ToString(); 45 }
运行、点击按钮、打开word效果以下:
总结
以上文章介绍的是没有经过组件将数据输出到word上,若是客户需求简单,格式不是太难控制彻底能够根据文章中经过模板的方式输出到word。其中最容易出问题的我认为就是编码问题,模板格式不同可能程序中的编码格式也要作相应的调整。
虽然以上方式演示没问题,可是实际开发中需求并无上面的例子简单。若是客户要求的word版式比较复杂,且数据要循环输出那么经过上面任何一种方式都很差解决。可是经过第三方组件就能够解决这种问题,若是这个组件用熟练了,上面的方式我相信你几乎不会用的。下一篇文章将介绍用第三方组件的方式把内容输出到word。