項目須要引用NPOI的Nuget包:DotNetCore.NPOI-v1.2.2前端
A-前端觸發下載Excel的方法有三種:ajax
1-JS-Url跳轉請求-後臺須要返回文件流數據:數據庫
window.Location.href = "/ajax/toolhelper.js?action=reBuyExport&beginTime=" + beginTime + "&endTime=" + endTime;
2-使用form+iframe請求文件流-後臺須要返回文件流數據:緩存
<form target="downLoadIframe" method="post" action="/ajax/toolhelper.js?action=reBuyExport"> <div class="form-group"> <label for="datetime">beginTime:</label> <input type="date" class="form-control" name="beginTime" placeholder="Enter beginTime" /> </div> <div class="form-group"> <label for="datetime">endTime:</label> <input type="date" class="form-control" name="endTime" placeholder="Enter endTime"> </div> <button type="submit" class="btn btn-primary" id="btnExport">導出Excel</button> </form> <iframe id="downLoadIframe" name="downLoadIframe" style="display:none;"></iframe>
3-JS-Fetch請求使用Blob保存二進制文件流數據,經過A標籤下載流文件-後臺須要返回文件流數據:服務器
領導推薦這種方法,通過檢驗的,能夠應對大文件下載的超時問題app
fetch(url).then(function (res) { res.blob().then(function (blob) { var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); a.href = url; a.download = fileName; a.click(); window.URL.revokeObjectURL(url); }); });
B-後臺返回流數據:async
Core下的Excel幫助類ide
/// <summary> /// EXCEL幫助類 /// </summary> /// <typeparam name="T">泛型類</typeparam> /// <typeparam name="TCollection">泛型類集合</typeparam> public class ExcelHelp<T, TCollection> where TCollection : List<T> where T : new() { public static ExcelHelp<T, TCollection> INSTANCE = new ExcelHelp<T, TCollection>(); //獲取httpResponse對象原位置,放在這裏不知道會報錯:服務器沒法在發送 HTTP 標頭以後追加標頭 //多是這裏拿到的httpResponse對象不是最新請求的對象致使的,將其放到方法內部便可 //HttpResponse baseResponse = HttpContext.Current.Response; /// <summary> /// 將數據導出EXCEL /// </summary> /// <param name="tList">要導出的數據集</param> /// <param name="fieldNameAndShowNameDic">鍵值對集合(鍵:字段名,值:顯示名稱)</param> /// <param name="httpResponse">響應</param> /// <param name="excelName">文件名(必須是英文或數字)</param> /// <returns></returns> public async Task ExportExcelData(TCollection tList, Dictionary<string, string> fieldNameAndShowNameDic, HttpResponse httpResponse, string excelName = "exportResult") { IWorkbook workbook = new HSSFWorkbook(); ISheet worksheet = workbook.CreateSheet("sheet1"); List<string> columnNameList = fieldNameAndShowNameDic.Values.ToList(); //設置首列顯示 IRow row1 = worksheet.CreateRow(0); ICell cell = null; ICellStyle cellHeadStyle = workbook.CreateCellStyle(); //設置首行字體加粗 IFont font = workbook.CreateFont(); font.Boldweight = short.MaxValue; cellHeadStyle.SetFont(font); for (var i = 0; i < columnNameList.Count; i++) { cell = row1.CreateCell(i); cell.SetCellValue(columnNameList[i]); cell.CellStyle = cellHeadStyle; } //根據反射建立其餘行數據 var raws = tList.Count; Dictionary<int, PropertyInfo> indexPropertyDic = this.GetIndexPropertyDic(fieldNameAndShowNameDic.Keys.ToList()); for (int i = 0; i < raws; i++) { row1 = worksheet.CreateRow(i + 1); for (int j = 0; j < fieldNameAndShowNameDic.Count; j++) { cell = row1.CreateCell(j); if (indexPropertyDic[j].PropertyType == typeof(int) || indexPropertyDic[j].PropertyType == typeof(decimal) || indexPropertyDic[j].PropertyType == typeof(double)) { cell.SetCellValue(Convert.ToDouble(indexPropertyDic[j].GetValue(tList[i]))); } else if (indexPropertyDic[j].PropertyType == typeof(DateTime)) { cell.SetCellValue(Convert.ToDateTime(indexPropertyDic[j].GetValue(tList[i]).ToString())); } else if (indexPropertyDic[j].PropertyType == typeof(bool)) { cell.SetCellValue(Convert.ToBoolean(indexPropertyDic[j].GetValue(tList[i]).ToString())); } else { cell.SetCellValue(indexPropertyDic[j].GetValue(tList[i]).ToString()); } } //設置行寬度自適應 worksheet.AutoSizeColumn(i, true); } MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/vnd.ms-excel"); mediaType.Encoding = System.Text.Encoding.UTF8; httpResponse.ContentType = mediaType.ToString(); //設置導出文件名 httpResponse.Headers.Add("content-disposition", $"attachment;filename={excelName}.xls"); MemoryStream ms = new MemoryStream(); workbook.Write(ms); //這句代碼很是重要,若是不加,會報:打開的EXCEL格式與擴展名指定的格式不一致 ms.Seek(0, SeekOrigin.Begin); byte[] myByteArray = ms.GetBuffer(); httpResponse.Headers.Add("Content-Length", myByteArray.Length.ToString()); await httpResponse.Body.WriteAsync(myByteArray, 0, myByteArray.Length); } /// <summary> /// 根據屬性名順序獲取對應的屬性對象 /// </summary> /// <param name="fieldNameList"></param> /// <returns></returns> private Dictionary<int, PropertyInfo> GetIndexPropertyDic(List<string> fieldNameList) { Dictionary<int, PropertyInfo> indexPropertyDic = new Dictionary<int, PropertyInfo>(fieldNameList.Count); List<PropertyInfo> tPropertyInfoList = typeof(T).GetProperties().ToList(); PropertyInfo propertyInfo = null; for (int i = 0; i < fieldNameList.Count; i++) { propertyInfo = tPropertyInfoList.Find(m => m.Name.Equals(fieldNameList[i], StringComparison.OrdinalIgnoreCase)); indexPropertyDic.Add(i, propertyInfo); } return indexPropertyDic; } }
Core的中間件請求方法:post
TBDataHelper爲提早注入的數據庫幫助類,須要改爲本身的數據請求類;字體
自定義的導出文件名,不能輸入中文,暫時尚未找到解決辦法;
BaseMiddleware爲基類,切記基類中只能存常態化的數據,如:下一中間件,配置,緩存。不能存放Request,Response等!!!
public class ToolHelperMiddleware : BaseMiddleware { public TBDataHelper TBDataHelper { get; set; } public ToolHelperMiddleware(RequestDelegate next, ConfigurationManager configurationManager, IMemoryCache memoryCache, TBDataHelper tBDataHelper) : base(next, configurationManager, memoryCache) { this.TBDataHelper = tBDataHelper; } public async Task Invoke(HttpContext httpContext) { var query = httpContext.Request.Query; var queryAction = query["action"]; switch (queryAction) { case "reBuyExport": await this.ReBuyExport(httpContext); break; } } /// <summary> /// 復購數據導出 /// </summary> /// <param name="httpContext"></param> /// <returns></returns> private async Task ReBuyExport(HttpContext httpContext) { var request = httpContext.Request; var response = httpContext.Response; var requestForm = request.Form; try { DateTime beginTime = Convert.ToDateTime(requestForm["beginTime"]); DateTime endTime = Convert.ToDateTime(requestForm["endTime"]); List<RebuyModel> rebuyModelList = this.TBDataHelper.SelectReBuyList(beginTime, endTime); Dictionary<string, string> fieldNameAndShowNameDic = new Dictionary<string, string>(0); fieldNameAndShowNameDic.Add("UserID", "用戶ID"); fieldNameAndShowNameDic.Add("PayCount", "支付數"); fieldNameAndShowNameDic.Add("BeforeBuyCount", beginTime.ToString("MM/dd") + "以前支付數"); string fileName = $"{beginTime.ToString("MMdd")}_{endTime.ToString("MMdd")}ReBuyExport_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"; await ExcelHelp<RebuyModel, List<RebuyModel>>.INSTANCE.ExportExcelData(rebuyModelList, fieldNameAndShowNameDic, response, fileName); } catch (Exception e) { throw e; } } }
/// <summary> /// 中間件基類 /// </summary> public abstract class BaseMiddleware { /// <summary> /// 等同於ASP.NET裏面的WebCache(HttpRuntime.Cache) /// </summary> protected IMemoryCache MemoryCache { get; set; } /// <summary> /// 獲取配置文件裏面的配置內容 /// </summary> protected ConfigurationManager ConfigurationManager { get; set; } /// <summary> /// 下一個中間件 /// </summary> protected RequestDelegate Next { get; set; } public BaseMiddleware(RequestDelegate next, params object[] @params) { this.Next = next; foreach (var item in @params) { if (item is IMemoryCache) { this.MemoryCache = (IMemoryCache)item; } else if (item is ConfigurationManager) { this.ConfigurationManager = (ConfigurationManager)item; } } } }