web頁面實現文件下載的幾種方法
今天碰到文件下載的一些問題,本着知其然也要知其所以然的精神,站在巨人的肩膀上深入學習和測試了一下,拋磚引玉,現在總結結論如下:
1)標准URL下載方式 可以通過在web頁面中嵌入 url超級鏈接,標准的HTTP GET請求,形如:“http://www.wjj.cc/test.zip” 的方式來下載。對於服務器端web根目錄有一個test.zip的文件。不解釋了,傻子都明白,看不明白就也沒有必要去搞IT了。 說明:此種方法的弊端是完全暴露了文件test.zip的網站路徑,而且動態性不夠靈活。網上已經很多資料,不多說了。
2)通過服務器端腳本向瀏覽器方(stdout)輸出二進制流的方式下載。比如 html頁面中嵌入URL為:http://www.wjj.cc/download.php&f=test.zip ,此方法是GET方式請求,URL完全可以獲取到。 說明:上述方法可以在服務器端 通過 腳本程序 download.php ,並且根據傳入的查詢字符串f=test.zip定位服務器上文件系統test.zip的路徑,然后按二進制流的方式發送給客戶端瀏覽器,那么客戶端瀏覽器就會彈出一個“下載對話框”了。 另一種方式是通過 提交表單,用POST方式提交參數到服務器端動態腳本,然后服務器端腳本返回輸出的二進制流到瀏覽器實現下載。尤其是當需要下載的文件(可能不一定是服務器上文件系統中具體的文件,有可能是服務器動態生成的數據) 依賴於客戶端提交的很多參數選項的時候,采用POST下載的方式是最多的。
下面重點講述通過動態腳本實現下載的一些例子,下面的例子中均沒有給出服務器端動態腳本的處理代碼:
1. GET URL下載鏈接,可以直接嵌入到 <a href="URL...">下載</a> 。 2. POST的URL下載鏈接,可以通過設置<form>表單的action 以及 表單元素值來完成下載。 3. 如果是GET方式的url下載鏈接,客戶端可以通過一個動態生成的隱藏的iframe來得到下載的二進制文件。原理是:iframe有一個src屬性,其本質就是發送http請求,GET一個頁面或者數據。javascript如下: function download(){ var IFrameRequest=document.createElement("iframe"); IFrameRequest.id="IFrameRequest"; IFrameRequest.src="/test.zip"; IFrameRequest.style.display="none"; document.body.appendChild(IFrameRequest); }
4. 用動態生成的form元素,實現表單提交,開完成下載。注意:此方法不是ajax哦。 參考url:http://www.cnblogs.com/sydeveloper/archive/2013/05/14/3078295.html 要說明的是,這里的原理僅僅是form提交表單,而不是ajax。
由於jQuery的ajax函數、及ajaxSubmit等函數的返回類型(dataType)只有xml、text、json、html等類型,沒有“流”類型,故我們要實現ajax下載時,不能夠使用相應的ajax函數進行文件下載。
在網上看了一些文章,發現可以通過js生成一個form,用這個form提交參數,並返回“流”類型的數據。在實現過程中,頁面也沒有進行刷新。
請看實例:
var form = $("<form>"); //定義一個form表單 form.attr('style','display:none'); //下面為在form表單中添加查詢參數 form.attr('target',''); form.attr('method','post'); form.attr('action',"exportSms"); var input1 = $('<input>'); input1.attr('type','hidden'); input1.attr('name','exportPostTime'); input1.attr('value',timeString); $('body').append(form); //將表單放置在web中 form.append(input1); //將查詢參數控件提交到表單上 form.submit(); //表單提交
jsp頁面上的txt附件,點擊后瀏覽器默認直接打開,結果是亂碼。
因為用戶上傳的txt文件可能是ANSI、Unicode、UTF-8編碼的任意一種,上傳時后台獲取文件內容重寫一遍保證瀏覽器打開正常太過麻煩,
同時也覺得下載到本地更為合適,所以希望實現點擊下載。
最初的實現方式是在Web.xml中配置mime-type,如下:
<mime-mapping> <extension>txt</extension> <mime-type>application/txt</mime-type> </mime-mapping>
但是最后發現在IE6上無效,仍然是直接打開,只好尋求新的方法。最后使用如題的方式解決,參考了
http://www.cnblogs.com/sydeveloper/archive/2013/05/14/3078295.html這里的文章。
代碼如下:
頁面js:下面是我工程中實際用到的:其中fnDownLoadJsonFile為button的onclick調用的函數,tbl為button所在的容器,此處為table.
function fnDownLoadJsonFile(tbl){ var $json_dir=$(tbl).parents('tr').children('td'); var jsonfiledir=$json_dir.eq(1).text(); var filenames; filenames=jsonfiledir.split("/"); var filename=filenames[filenames.length-1]; var uri="../NetworkServlet?ActionId=7&JsonFileDir="+jsonfiledir; / downFile(jsonfiledir); return; } function downFile(filePath){ var form=$("<form>");//定義一個form表單 form.attr("style","display:none"); form.attr("target",""); form.attr("method","post"); form.attr("action","../NetworkServlet?ActionId=7"); var input1=$("<input>"); input1.attr("type","hidden"); input1.attr("name","JsonFileDir"); input1.attr("value",filePath); $("body").append(form);//將表單放置在web中 form.append(input1); form.submit();//表單提交 form.remove(); }
Java servlet :
private void doActionDownLoadFileJson(HttpServletRequest request, HttpServletResponse response) throws IOException { // TODO Auto-generated method stub Context ctx = (android.content.Context) conf.getServletContext() .getAttribute("org.mortbay.ijetty.context"); String mJsonFileDir; mJsonFileDir = request.getParameter("JsonFileDir"); String filenames[] = mJsonFileDir.split("/"); String filename = null; if (filenames.length > 1) { filename = filenames[filenames.length - 1]; } // 設置下載的類型 告訴瀏覽器 需要以下載的方式操作 response.setContentType("application/force=download"); // 下載頭設置 response.setHeader("content-disposition", "attachment;fileName=" + java.net.URLEncoder.encode(filename, "UTF-8")); File file = new File(mJsonFileDir); // 創建輸入流對象 java.io.FileInputStream fileInputStream = null; ServletOutputStream sos = null; PrintWriter writer = null; try { fileInputStream = new java.io.FileInputStream(file); writer = response.getWriter(); // response.getOutputStream(); int i; while ((i = fileInputStream.read()) != -1) { writer.write(i); } writer.flush(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (sos != null) { try { sos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (writer != null) { writer.close(); } } return; }
里面用的服務器為Jetty app服務器.兼容多個瀏覽器....
其中有兩點需要注意:
<1> : 第一點就是jquery的ajax不支持下載文件,上面紅色處已表明;
<2> : 后台的getOutStream是不能夠使用的,否則會和文件流沖突;