做導出一直遇到個問題就是不能用ajax實現一步導出文檔,即導出加下載。今天突然想到可以分開來做就上網搜了下,發現一篇比較不錯的文章(
http://www.cnblogs.com/zj0208/p/5961181.html
),先摘錄下來。
問題說明:Ajax是無法實現文件傳輸的,本文只是模擬了Ajax不刷新頁面就可以請求並返回數據的效果。實質上還是通過提交form表單來返回文件流的輸出。
分步實現邏輯:
- ajax請求服務器,訪問數據庫,根據查詢到的數據生成一個數據文件,返回前台一個json對象(可放置生成成功標記,文件路徑等信息)。
- ajax success回調函數部分,根據返回的json對象,調用手寫的js下載文件的方法,實現頁面無刷新下載文件。
貼上部分代碼供參考:
js代碼:
1. js寫一個動態創建並提交form表單的方法,依賴於jQuery插件。
// 文件下載 jQuery.download = function (url, method, filedir, filename) { jQuery('<form action="' + url + '" method="' + (method || 'post') + '">' + // action請求路徑及推送方法 '<input type="text" name="filedir" value="' + filedir + '"/>' + // 文件路徑 '<input type="text" name="filename" value="' + filename + '"/>' + // 文件名稱 '</form>') .appendTo('body').submit().remove(); };
2. 查詢數據,輸出到文件,保存到服務器,並調用download方法實現下載
//ajax交互導出文檔並獲取文檔路徑及預下載文件名,返回格式{\"result\":\"success\",\"filePath\":\"\",\"fileName\":\"\"} function DownFilesAjax(url, prams, downurl) { showLoading(true);//調用加載動畫http://spin.js.org/ $.ajax({ type: 'POST', dataType: 'json', async: false, url: url,// 生成文件,保存在服務器 data: prams, success: function (data) { if (data.result == "success") { $.download(downurl, 'post', data.filePath, data.fileName); // 下載文件 showLoading(false);//隱藏加載動畫http://spin.js.org/ } else { alert("數據導出失敗!"); showLoading(false); } }, error: function (XMLHttpRequest, textStatus, e) { //console.log("oilDetection.js method exportOilDetection" + e); alert("數據傳輸發生錯誤,請聯系管理員!"); showLoading(false); } }); }
附上spin加載動畫調用js及其容器的遮罩樣式。
調用js:
var opts = { lines: 9, // 花瓣數目 length: 0, // 花瓣長度 width: 10, // 花瓣寬度 radius: 15, // 花瓣距中心半徑 corners: 1, // 花瓣圓滑度 (0-1) rotate: 0, // 花瓣旋轉角度 direction: 1, // 花瓣旋轉方向 1: 順時針, -1: 逆時針 color: '#fff', // 花瓣顏色 speed: 1, // 花瓣旋轉速度 trail: 60, // 花瓣旋轉時的拖影(百分比) shadow: false, // 花瓣是否顯示陰影 hwaccel: false, //spinner 是否啟用硬件加速及高速旋轉 className: 'spinner', // spinner css 樣式名稱 easyui里用這個類樣式,若引用了easyui.css務必換個類名,其他前端框架未知 zIndex: 2e9, // spinner的z軸 (默認是2000000000) top: '50%', // spinner 相對父容器Top定位 單位 px left: '50%'// spinner 相對父容器Left定位 單位 px }; var spinner = new Spinner(opts); //顯示與隱藏加載動畫 function showLoading(result) { var spinContainer = document.getElementById("foo"); if (result) { var target = $(spinContainer).get(0); spinner.spin(target); spinContainer.style.height = document.documentElement.clientHeight + "px"; $(spinContainer).show(); } else { spinner.spin(); $(spinContainer).hide(); } }
遮罩樣式:
#foo { position: fixed; left: 0; top: 0; _position: absolute; width: 100%; background: #000; opacity: 0.5; filter: alpha(opacity=50); z-index: 999; display:none; }
以下一般處理程序中的相關代碼。
導出文檔:
public void ExportALLNianDuGongZuo(HttpContext context) { string result = string.Empty; string Name = DateTime.Now.Year + "導出的文件" + ".xls";//下載文檔名 try { #region 導出過程 DataTable dt = new DataTable(); DataColumn dc = null; dc = dt.Columns.Add("序號", Type.GetType("System.Int32")); dc.AutoIncrement = true;//自動增加 dc.AutoIncrementSeed = 1;//起始為1 dc.AutoIncrementStep = 1;//步長為1 dc.AllowDBNull = false;// dc = dt.Columns.Add("col1", Type.GetType("System.String")); dc = dt.Columns.Add("col2", Type.GetType("System.String")); dc = dt.Columns.Add("col3", Type.GetType("System.String")); dc = dt.Columns.Add("col4", Type.GetType("System.String")); dc = dt.Columns.Add("col5", Type.GetType("System.String")); IList<object> list = object.FindAll(@"IsEnable=1", "GOrder, PaiXu", null, 0, 0);//數據列表 foreach (var item in list) { DataRow newRow; newRow = dt.NewRow(); newRow["col1"] = item.Name; newRow["col2"] = item.Ext3; newRow["col3"] = item.XieZuoDeptName; newRow["col4"] = item.Ext2; newRow["col5"] = IsShangHui.Trim(); dt.Rows.Add(newRow); } MemoryStream ms = new MemoryStream(); string Path = context.Server.MapPath("~/UploadFile/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls");//文件保存地址 string templatePath = context.Server.MapPath("~/UploadFile/模版.xls");//所用模版地址 ms = NPOIExcelHelper.DataTableToExcel(dt, templatePath, 2);//詳見NPOI導出execl using (FileStream fs = new FileStream(Path, FileMode.Create, FileAccess.Write)) { byte[] data = ms.ToArray(); fs.Write(data, 0, data.Length); fs.Flush(); } #endregion result = "{\"result\":\"success\",\"filePath\":\"" + ReplaceString(Path) + "\",\"fileName\":\"" + Name + "\"}"; } catch (Exception ex) { result = "{\"result\":\"fail\"}"; Unionstars.Trace.Log.WriteLine("導出發生錯誤:【" + ex + "】"); } context.Response.ContentType = "application/Json"; context.Response.Write(result); context.Response.End(); }
ajax無法傳輸文件,另新建web頁面用來下載即可。
下載文檔頁面后台代碼(前台刪得只剩第一句即可):
protected void Page_Load(object sender, EventArgs e) { string fileName = Request["filename"];//下載文檔名 string filePath = Request["filedir"]; FileInfo fileInfo = new FileInfo(filePath); Response.Clear(); Response.ClearContent(); Response.ClearHeaders(); String userAgent = System.Web.HttpContext.Current.Request.UserAgent; //判斷是否為ie10以下及ie11瀏覽器 if (userAgent.Contains("MSIE") || userAgent.Contains("rv:11")) { fileName = System.Web.HttpUtility.UrlEncode(fileName); } Response.AddHeader("Content-Disposition", string.Format("attachment;filename=\"{0}\"", fileName)); Response.AddHeader("Content-Length", fileInfo.Length.ToString()); Response.AddHeader("Content-Transfer-Encoding", "binary"); Response.ContentType = "application/octet-stream"; Response.ContentEncoding = System.Text.Encoding.GetEncoding("gb2312"); Response.WriteFile(fileInfo.FullName); Response.Flush(); Response.End(); }
終極方法,哈哈哈,留到最后
function download(url, downLoadFileRename) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); // 也可以使用POST方式,根據接口 xhr.responseType = "blob"; // 返回類型blob // 定義請求完成的處理函數,請求前也可以增加加載框/禁用下載按鈕邏輯 xhr.onload = function () { // 請求完成 if (this.status === 200) { // 返回200 var blob = this.response; var reader = new FileReader(); reader.readAsDataURL(blob); // 轉換為base64,可以直接放入a表情href reader.onload = function (e) { // 轉換完成,創建一個a標簽用於下載 var a = document.createElement('a'); a.download = downLoadFileRename; a.href = e.target.result; $("body").append(a); // 修復firefox中無法觸發click a.click(); $(a).remove(); } } }; // 發送ajax請求 xhr.send() }