jsp中實現文件下載,最簡單的方式是在網頁上做超級鏈接,如:<a href="music/abc.mp3">點擊下載</a>。 但是,這樣服務器上的目錄資源會直接暴露給最終用戶,會給網站帶來一些不安全的因素。 因此,可以采用其它方式實現下載,常使用的有以下兩種:
1、RequestDispatcher的方式進行;
2、采用文件流輸出的方式下載(推薦)。
1、采用RequestDispatcher的方式:
2、采用文件流輸出的方式下載
對於第二種方法,我認為應該是比較常用的。不過有幾個地方是值得我們注意的:
1、采用第二種方法的主要優點是實際文件的存放路徑對客戶端來說是透明的。
這個文件可以存在於任何你的服務器能夠取得到的地方,而客戶端不一定能直接得到。例如文件來自於數據庫或者內部網絡的一個FTP服務器。還句話說,這種方式可以實現隱藏實際文件的URL地址。
2、為了防止客戶端瀏覽器直接打開目標文件。
例如在裝了MS Office套件的Windows中的IE瀏覽器可能就會直接在IE瀏覽器中打開你想下載的doc或者xls文件。你必須在響應頭里加入強制下載的MIME類型:response.setContentType("application/force-download"); //設置為下載application/force-download。這樣,就可以保證在用戶點擊下載鏈接的時候瀏覽器一定會彈出提示窗口來詢問你是下載還是直接打開並允許你選擇要打開的應用程序,除非你設置了瀏覽器的一些默認行為。 或者,你想讓客戶端自行處理各種不同的文件類型,你可以在服務器的配置文件中配置MIME類型映射,通過簡單的判斷文件后綴名來處理。例如,在Tomcat中設置MIME響應類型: 如果文件在客戶端中的響應程序類型和期望不一致,修改$TOMCAT_HOME\conf\web.xml文件中的如下部分 :
1 <span style="font-family:Arial;font-size:12px;"><mime-mapping> 2 <extension>zip</extension> 3 <mime-type>application/zip</mime-type> 4 </mime-mapping> 5 <mime-mapping> 6 <extension>mht</extension> 7 <mime-type>message/rfc822</mime-type> 8 </mime-mapping> 9 …… </span>
3、在響應頭中盡量不要設置瀏覽器緩存期限。
有時候用戶在點擊了下載鏈接后,在彈出窗口中,用戶想直接點擊“打開”,而不想保存到指定路徑。這時候如果我們在響應頭中限制了不允許使用瀏覽器緩存(即總是刷新),在IE瀏覽器中我們將無法直接打開該文件。因為限制了不允許使用緩存,瀏覽器無法將文件保存到臨時文件夾(即緩存)。也就是說,在響應頭中不要進行如下的設置(已注釋):
1 <span style="font-family:Arial;font-size:12px;"> //response.addHeader("pragma","NO-cache"); 2 //response.addHeader("Cache-Control","no-cache"); 3 //response.addDateHeader("Expries",0);</span>
4、文件名為中文或其他unicode字符時的處理。
有時候提供下載的文件名中包含中文字符或者其他unicode字符,會導致瀏覽器無法正確的采用默認的文件名保存文件。我們應該記住在響應頭中包含filename字段並采用ISO8859-1編碼(推薦)或者采用UTF-8編碼:
1 response.setHeader("Content-disposition","attachment; filename="+new String(filename.getBytes("UTF-8"),"iso8859-1")); //采用ISO8859-1編碼 2 response.setHeader("Content-disposition","attachment; filename="+URLEncoder.encode(filename, "UTF-8")); //采用UTF-8編碼
但是,這種方式在不同的瀏覽器中表現也有所不同。例如在IE和Firefox中,采用ISO8859-1編碼可以正確顯示文件名,而在Opera中不管采用那種編碼,默認保存的文件名都無法做到正確顯示。 所以,最好的方法其實就是盡量在文件名中使用ascii編碼。
5、由於采用流的方式進行輸入輸出,我們必須保證在使用完畢后關閉流的資源。
一般我們把關閉流的操作放在finally塊中,以保證在程序段結束前一定會關閉流的資源。如下面代碼:
1 InputStream is = null; 2 ServletOutputStream sos = null; 3 try { 4 is = ...; //通過某種方式讀進數據到輸入流 5 os = response.getOutputStream(); //打開輸出流 6 byte[] buff = new byte[2048]; 7 int bytesRead=0; 8 while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) { 9 os.write(buff,0,bytesRead); 10 os.flush(); 11 } 12 } catch(Exception ex) { 13 //TODO something with Exception 14 } finally { 15 if(is != null) { 16 is.close(); //關閉輸入流 17 } 18 if(os != null) { 19 os.close(); //關閉輸入流 20 } 21 }