文章出處

項目開發過程中,我們要把數據以各種各樣的形式展現給客戶。把數據以文檔的形式展現給客戶相信是一種比較頭疼的問題,如果沒有好的方法會

使得我的開發繁瑣,而且滿足不了客戶的需求。接下來我會通過兩種開發方式介紹如何將數據輸出到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="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>
View Code

 

后端代碼輸出到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         }
View Code

 運行、點擊按鈕、打開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。

 

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()