• 把数据输出到Word (非插件形式)


    项目开发过程中,我们要把数据以各种各样的形式展现给客户。把数据以文档的形式展现给客户相信是一种比较头疼的问题,如果没有好的方法会

    使得我的开发繁琐,而且满足不了客户的需求。接下来我会通过两种开发方式介绍如何将数据输出到Word 文档上。我会分两篇文章介绍,第一篇

    介绍不使用插件的情况下操作word,第二篇文章将介绍一种强大的插件操作word。下面开始第一篇文章。[本次实例源代码从这里下载]

    文章梗概:

    ♦ 不使用模板将数据输出到 word

         ♦ 输出数据到 word 在后端设置输出内容

         ♦ 输出数据到 word 在前端设置输出内容

    ♦ 通过设置模板将数据输出到 word

         ♦ 通过把word另存为html 文件的形式做成模板输出到word

         ♦ 通过把word另存为mht 文件的形式做成模板输出到word

    一、不用模板将数据输出到 word

    1、输出数据到 word 在后端设置输出内容

    前端定义两个服务器按钮:

    复制代码
    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文档,效果如下:

    2、输出数据到 word 在前端设置输出内容

    前端设置输出的html内容。以输出一个表格为例。其中有两个div 标记了runat="server",这样后台就可以取到这个id,用途一会介绍。

    复制代码
     1 <div id="WordContent" runat="server">
     2         <div runat="server" id="title">表头</div>
     3         <table border="1" style="400px;line-height: 25px;">
     4             <tr style="400px; height:25px;">
     5                 <td>
     6                     编号
     7                 </td>
     8                 <td>
     9                     姓名
    10                 </td>
    11                 <td>
    12                     成绩
    13                 </td>
    14             </tr>
    15             <tr style="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="400px;line-height: 25px;">
     5             <tr style="400px; height:25px;">
     6                 <td>
     7                     编号
     8                 </td>
     9                 <td>
    10                     姓名
    11                 </td>
    12                 <td>
    13                     成绩
    14                 </td>
    15             </tr>
    16             <tr style="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模板把要输出的内容填充进去将会大大的缩短我们的时间,最主要的是版式不用我们太关心。

    1、 通过把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,效果如下

     

    2、 通过把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。

  • 相关阅读:
    XmlNode中Value和InnerText的区别
    C# 后台POST和GET 获取数据
    XDocument简单入门
    一个基于jQuery的简单树形菜单
    使用C#的HttpWebRequest模拟登陆网站
    JS中offsetTop、clientTop、scrollTop、offsetTop各属性介绍
    height、clientHeight、scrollHeight、offsetHeight区别
    使用httpwebrequest Post数据到网站
    sql语句中left join、inner join中的on与where的区别
    SQL Join的一些总结
  • 原文地址:https://www.cnblogs.com/lyl6796910/p/3721946.html
Copyright © 2020-2023  润新知