本文來自:http://www.cnblogs.com/hipo/archive/2012/03/13/2394019.html
一、關於下載
一般對下載權限有沒有限制,或安全性要求不高的情況下,基於web的下載可以直接采用提供服務器文件路徑的方式,瀏覽器端就可以下載。當然對於這種方式的弊端顯而易見,用戶可以獲得下載文件在服務器端的絕對路徑,下載的權限也沒有辦法進行控制。如果你的網站提供的下載有復雜的邏輯判斷,那么這種方式就不能解決問題。
要解決這個問題,我們可以采用以文件流的方式提供下載。客戶端發出下載請求,在服務器端收到請求后,找到后台相應的處理邏輯代碼,首先驗證請求是否符合下載條件,在做出相應的相應。若驗證成功,將請求下載文件轉化為文件流,傳給瀏覽器;若不成功,直接拒絕下載。
在ASP.Net 中這個HTTP請求的后台處理邏輯,可用一般處理文件*.ashx。這個文件的抽象度沒有.aspx那么高,相比之下比較原始,所以我們可以自定義處理邏輯。
下面來分析下ASP.Net MVC況下,關於安全下載的實現。ASP.Net MVC已經為我們做好封裝,即FileResult ,但是FileResult是個抽象,而具體包括FilePathResult、FileStreamResult、FileContentResult三個之類,可向客戶端傳送文件(二進制形式),例如存在服務器磁盤word文檔,或者存儲在數據庫中巨大數據等。只需要設置FileDownloadName屬性,就可以達到添加HTTP報頭的作用,在客戶端出現下載對話框。當具體實現的時候,可以使用工廠模式。
二、數據庫導出Excel
目前,常用的數據庫導出Excel的方法,是借助第三方的類庫。第三類庫中很重要的一個就是PIO,是Apache下一個開源項目,提供一個Java類庫對Microsoft Office進行讀寫操作。當然,這里要介紹的不是PIO,而是.Net環境下,基於PIO的NPIO,可以理解為.Net POI。NPOI是微軟開源社區CodePlex的一個開源項目,旨在提供.net平台上操作Office的服務。
點擊這里參看NPOI的教程文檔。
2. 在NPOI中包括了兩個dll:Ionic.Zip.dll和NPOI.dll。
三、一個ASP.Net MVC 2.0下導出Excel並提供下載的例子
通過以下幾步,建立一個項目:
1. 創建ASP.Net MVC 2.0項目SQLServer2Excel;
2. 添加對於NPOI類庫的引用,包括Ionic.Zip.dll和NPOI.dll;
3.鏈接本地數據庫Test,在web.config做如下配置:
1: <connectionStrings>
2: <add name="TestConnectionString" connectionString="Data Source=(local);Initial Catalog=Test;Integrated Security=True"3: providerName="System.Data.SqlClient" />4: </connectionStrings>
通過以上幾步,我們已經建立了基本環境,下面我們來中點介紹下NPOI和FileResult的使用:
1.寫NPOI導出方法,首先必須using命名空間NPOI.SS.UserModel和NPOI.HSSF.UserModel。在這個例子中,NPOI將輸入DataSet對象,轉化為Excel表格,並且保存了MemoryStream的內存流對象,這樣做的好處:在提供下載的同時,不會在服務器端產生中間文件。
這里采用的是以基於Column和Row的方式解析Dataset對象的。
1: using System;2: using System.Collections.Generic;3: using System.Linq;4: using System.Web;5: using System.IO;6: using NPOI.SS.UserModel;7: using NPOI.HSSF.UserModel;8: using System.Data;9:
10: namespace SQLServer2Excel.Models11: {
12: public class ExportTool13: {
14: /// <summary>15: /// 將DataSet數據集轉換HSSFworkbook對象,並保存為Stream流16: /// </summary>17: /// <param name="ds"></param>18: /// <returns>返回數據流Stream對象</returns>19: public static MemoryStream ExportDatasetToExcel(DataSet ds)20: {
21: try22: {
23: //文件流對象24: MemoryStream stream = new MemoryStream();25:
26: //打開Excel對象27: HSSFWorkbook workbook = new HSSFWorkbook();28:
29: //Excel的Sheet對象30: NPOI.SS.UserModel.Sheet sheet = workbook.CreateSheet("sheet1");31:
32: //set date format33: CellStyle cellStyleDate = workbook.CreateCellStyle();
34: DataFormat format = workbook.CreateDataFormat();
35: cellStyleDate.DataFormat = format.GetFormat("yyyy年m月d日");36:
37: //使用NPOI操作Excel表38: NPOI.SS.UserModel.Row row = sheet.CreateRow(0);
39: int count = 0;40: for (int i = 0; i < ds.Tables[0].Columns.Count; i++) //生成sheet第一行列名41: {
42: NPOI.SS.UserModel.Cell cell = row.CreateCell(count++);
43: cell.SetCellValue(ds.Tables[0].Columns[i].Caption);
44: }
45: //將數據導入到excel表中46: for (int i = 0; i < ds.Tables[0].Rows.Count; i++)47: {
48: NPOI.SS.UserModel.Row rows = sheet.CreateRow(i + 1);
49: count = 0;
50: for (int j = 0; j < ds.Tables[0].Columns.Count; j++)51: {
52: NPOI.SS.UserModel.Cell cell = rows.CreateCell(count++);
53: Type type = ds.Tables[0].Rows[i][j].GetType();
54: if (type == typeof(int) || type == typeof(Int16)55: || type == typeof(Int32) || type == typeof(Int64))56: {
57: cell.SetCellValue((int)ds.Tables[0].Rows[i][j]);58: }
59: else60: {
61: if (type == typeof(float) || type == typeof(double) || type == typeof(Double))62: {
63: cell.SetCellValue((Double)ds.Tables[0].Rows[i][j]);
64: }
65: else66: {
67: if (type == typeof(DateTime))68: {
69: cell.SetCellValue(((DateTime)ds.Tables[0].Rows[i][j]).ToString("yyyy-MM-dd HH:mm"));70: }
71: else72: {
73: if (type == typeof(bool) || type == typeof(Boolean))74: {
75: cell.SetCellValue((bool)ds.Tables[0].Rows[i][j]);76: }
77: else78: {
79: cell.SetCellValue(ds.Tables[0].Rows[i][j].ToString());
80: }
81: }
82: }
83: }
84: }
85: }
86:
87: //保存excel文檔88: sheet.ForceFormulaRecalculation = true;89:
90: workbook.Write(stream);
91: workbook.Dispose();
92:
93: return stream;94: }
95: catch96: {
97: return new MemoryStream();98: }
99: }
100: }
101: }
2. FileResult的使用,這里實際上用到的是其之類FileStreamResult。
1: public FileResult DownloadFile()2: {
3: DataSet ds = Person.GetPersonDataSet(new DataSet());4:
5: MemoryStream stream = ExportTool.ExportDatasetToExcel(ds);
6: stream.Seek(0, SeekOrigin.Begin);
7:
8: return File(stream, "application/vnd.ms-excel", "spreadsheet1.xls");9: }
這里說明一下兩點: a. 第6行代碼的作用:如果沒有這行代碼,可能保存的數據大小為0kb,這是因為調整下輸出流的開始位置;b.第8行File()方法,此方法的各種重載方法,可以返回FileResult的之類對象。在這里第二參數“application/vnd.ms- excel”代表Excel文件,第三個參數給定文件名。