將數據導出到Excel,供用戶下載是常常要使用到的一個功能,我這裏進行了一些封裝,目前已知足項目中導出的需求,使用DataReader導出Excel,支持自定義多表頭,使用委託處理字段格式化及字段值的計算;前端
導出執行的代碼以下:數據庫
/// <summary> /// 將DataReader數據寫入到 excel book 中 /// 通常數據量小的導出用這個就能夠啦 /// </summary> /// <param name="dataReader"></param> /// <param name="book">Excel Book</param> /// <param name="excelName">excelName文件名字</param> /// <param name="sheetSize">每一個Sheet放多少條記錄</param> /// <param name="excelHeaderModels">Excel表頭實體,Select字段能夠從這裏獲取</param> /// <param name="func">字段格式化委託函數</param> /// <param name="funcCalc">字段的值計算委託函數</param> /// <returns></returns> public Hashtable CommonDataWrite2Sheet(IDataReader dataReader, IWorkbook book, string excelName, int sheetSize, List<ExcelHeaderModel> excelHeaderModels = null, Func<string, object, string> func = null, Func<string, object, IDataReader, object> funcCalc = null) { string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BusinessSystemInfo.ExportDir, DateTime.Now.ToString(BaseSystemInfo.DateFormat)); string fileName = Path.Combine(filePath, excelName); //建立表頭 int totalCount = 1; //表頭的要去掉 不然默認的是65535條記錄 一個表頭 因此從1開始 if (excelHeaderModels != null) { totalCount = excelHeaderModels.Max(c => c.RowStart) + 1; } Hashtable ht = new Hashtable(); //給book 建立Sheet int sheetIndex = 0; string sheetName = "sheet"; ISheet sheet = book.CreateSheet(sheetName + sheetIndex); //在建立的sheet裏面建立表頭 CreateHeader(dataReader, book, excelHeaderModels, sheet); //寫入到book中 逐行 while (dataReader.Read()) { // 輸出的總數量大於每頁數量(如65535),換一頁寫入 2003版本的纔會要求限制每sheet放65535條記錄 if (book.GetType() == typeof(HSSFWorkbook)) { if (totalCount > sheetSize) { //換一頁寫 sheetIndex++; totalCount = 0; sheet = book.CreateSheet(sheetName + sheetIndex); CreateHeader(dataReader, book, excelHeaderModels, sheet); } } //建立Excel的行這一行是sheet建立的第rowIndex++行 IRow excelRow = sheet.CreateRow(totalCount); for (int i = 0; i < dataReader.FieldCount; i++) { //在rowIndex++行的給第j列 寫入 dt的第i行第j列的值 ICell cell = excelRow.CreateCell(i); string colName = dataReader.GetName(i); object value = dataReader.GetValue(i); if (funcCalc != null) { value = funcCalc(colName, value, dataReader); } SetCellValue(func, cell, value, colName); } //自動調整單元格大小 有些耗時 //for (int i = 0; i < dataReader.FieldCount; i++) //{ // sheet.AutoSizeColumn(i,true); //} totalCount++; } // book寫入到文件中 WriteToFile(book, fileName); //獲取擴展名 //string fileExt = Path.GetExtension(fileName); //using (ZipFile zip = ZipFile.Create(fileName.Replace(fileExt, ".zip"))) //{ // zip.BeginUpdate(); // zip.SetComment("這是個人壓縮包"); // zip.Add(fileName); //添加一個文件 // zip.CommitUpdate(); //} fileName = fileName.Replace(AppDomain.CurrentDomain.BaseDirectory + "", ""); ht.Add("Code", "1"); ht.Add("Detail", "數據導出完畢,請下載。"); ht.Add("fileName", fileName); ht.Add("Count", totalCount); return ht; }
WriteToFile 將book寫入到文件的方法,注意,這裏使用了 ms.ToArray()。
/// <summary> /// Excel book寫入到Excel文件 /// </summary> /// <param name="book"></param> /// <param name="fileName"></param> /// <returns></returns> private bool WriteToFile(IWorkbook book, string fileName) { bool result = true; try { using (MemoryStream ms = new MemoryStream()) { string filePath = Path.GetDirectoryName(fileName); if (filePath != null && !Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } book.Write(ms); var buf = ms.ToArray(); using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { fs.Write(buf, 0, buf.Length); fs.Flush(); } } } catch (Exception e) { LogHelper.WriteErrorLog(e.Message, e); result = false; } finally { GC.Collect(); } return result; }
ExcelHeaderModel 是定義的表頭實體,支持自定義多表頭,以下:函數
/// <summary> /// 導出配置 /// /// 修改紀錄 /// /// 2015-12-19版本:1.0 SongBiao 建立文件。 /// /// <author> /// <name>SongBiao</name> /// <date>2015-12-19</date> /// </author> /// </summary> [Serializable] public class ExcelHeaderModel { /// <summary> /// 數據庫裏面的字段名稱 /// </summary> public string SrcName { get; set; } /// <summary> /// 名稱 /// </summary> public string Name { get; set; } /// <summary> /// 行開始 /// </summary> public int RowStart { get; set; } /// <summary> /// 行結束 /// </summary> public int RowEnd { get; set; } /// <summary> /// 列開始 /// </summary> public int ColStart { get; set; } /// <summary> /// 列結束 /// </summary> public int ColEnd { get; set; } /// <summary> /// 是否顯示在表頭 有些字段不須要顯示 可是須要用來作計算 /// </summary> [DefaultValue(false)] public bool Hidden { get; set; } }
Controller中的業務調用ui
/// <summary> /// 導出操做,支持導出當前頁,導出所有,導出文件格式excel2003,excel2007及以上 /// </summary> /// <param name="searchModel"></param> /// <param name="pager"></param> /// <param name="sort"></param> /// <param name="direction"></param> /// <param name="isPage">true:導出當前頁,false:導出所有</param> /// <returns></returns> [CustomerResource("ExportData")] public ActionResult ExportData(PriceSearchEntity searchModel, QuiGridPager pager, string sort, string direction,bool isPage) { PriceManager priceManager = new PriceManager(BusinessDbHelper, UserInfo); // 使用DataReader導出 IDataReader dr ; //要導出的字段 string selectField = GetExportField(); string tableName = PriceEntity.TableName + " A"; // 導出當前頁 if (isPage) { dr = priceManager.ExecuteReaderByPage(searchModel,tableName, pager, sort, direction, selectField); } else { dr = priceManager.ExecuteReader(searchModel, tableName, sort, direction, selectField); } using (dr) { IWorkbook book = new HSSFWorkbook(); // 2007的導出 // IWorkbook book = new XSSFWorkbook();//.xlsx string fileName = UserInfo.NickName+"_數據導出-" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".xls"; // GetSelectField() // 導出的文件自動壓縮 // var hashTable = new ExportHelper().DataWrite2Excel(dr, book, fileName, 5, 65530, null, null, null); //通常用這個 var hashTable = new ExportHelper().CommonDataWrite2Sheet(dr, book, fileName, 65530); hashTable.Add("TotalTime", CalcTimeSpan(StartTime)); return Json(hashTable, JsonRequestBehavior.AllowGet); } }
這裏使用了通用權限系統的權限控制功能及底層的數據訪問功能,解決導出權限控制的問題。spa
代碼裏可根據須要控制輸出的文件使用Excel2003仍是Excel2007的文件格式。excel
前端導出完成展現的效果:code