jsp中實現文件下載   兩種方法

jsp中實現文件下載                

 

               

轉自:http://aguu125.iteye.com/blog/352314

(一)
最簡單的方式是在網頁上做超級鏈接,如:<a href="music/abc.mp3">點擊下載</a>。
但是這樣服務器上的目錄資源會直接暴露給最終用戶,會給網站帶來一些不安全的因素。

因此可以採用其它方式實現下載,可以採用:
1、RequestDispatcher的方式進行;
2、採用文件流輸出的方式下載。 (推薦)

1、採用RequestDispatcher的方式進行
<% 
  response.setContentType("application/x-download");//設置爲下載application/x-download 
  String filedownload = "/要下載的文件名";//即將下載的文件的相對路徑 
  String filedisplay = "最終要顯示給用戶的保存文件名";//下載文件時顯示的文件保存名稱 
  String filenamedisplay = URLEncoder.encode(filedisplay,"UTF-8"); 
  response.addHeader("Content-Disposition","attachment;filename=" + filedisplay); 
    
  try 
  { 
  RequestDispatcher dis = application.getRequestDispatcher(filedownload); 
  if(dis!= null) 
  { 
  dis.forward(request,response); 
  } 
  response.flushBuffer(); 
  } 
  catch(Exception e) 
  { 
  e.printStackTrace(); 
  } 
  finally 
  { 
    
  } 
%> 


2、採用文件流輸出的方式下載 
<%@page language="java" contentType="application/x-msdownload" pageEncoding="gb2312"%> 
<% 
  //關於文件下載時採用文件流輸出的方式處理: 
  //加上response.reset(),並且所有的%>後面不要換行,包括最後一個; 
 
  response.reset();//可以加也可以不加 
  response.setContentType("application/x-download"); 
 
//application.getRealPath("/main/mvplayer/CapSetup.msi");獲取的物理路徑 
 
String filedownload = "想辦法找到要提供下載的文件的物理路徑+文件名"; 
String filedisplay = "給用戶提供的下載文件名"; 
  String filedisplay = URLEncoder.encode(filedisplay,"UTF-8"); 
  response.addHeader("Content-Disposition","attachment;filename=" + filedisplay); 
 
  java.io.OutputStream outp = null; 
  java.io.FileInputStream in = null; 
  try 
  { 
  outp = response.getOutputStream(); 
  in = new FileInputStream(filenamedownload); 
 
  byte[] b = new byte[1024]; 
  int i = 0; 
 
  while((i = in.read(b)) > 0) 
  { 
  outp.write(b, 0, i); 
  } 
//   
outp.flush(); 
//要加以下兩句話,否則會報錯 
//java.lang.IllegalStateException: getOutputStream() has already been called for //this response   
out.clear(); 
out = pageContext.pushBody(); 

  catch(Exception e) 
  { 
  System.out.println("Error!"); 
  e.printStackTrace(); 
  } 
  finally 
  { 
  if(in != null) 
  { 
  in.close(); 
  in = null; 
  } 
//這裏不能關閉   
//if(outp != null) 
  //{ 
  //outp.close(); 
  //outp = null; 
  //} 
  } 
%> 

對於第二種方法,我認爲應該是比較常用的。不過有幾個地方是值得我們注意的:

一、採用第二種方法的主要優點是實際文件的存放路徑對客戶端來說是透明的。
這個文件可以存在於任何你的服務器能夠取得到的地方,而客戶端不一定能直接得到。例如文件來自於數據庫或者內部網絡的一個FTP服務器。換句話說,這種方式可以實現隱藏實際文件的URL地址。

二、爲了防止客戶端瀏覽器直接打開目標文件(例如在裝了MS Office套件的Windows中的IE瀏覽器可能就會直接在IE瀏覽器中打開你想下載的doc或者xls文件),你必須在響應頭裏加入強制下載的MIME類型:
response.setContentType("application/force-download");//設置爲下載application/force-download
這樣,就可以保證在用戶點擊下載鏈接的時候瀏覽器一定會彈出提示窗口來詢問你是下載還是直接打開並允許你選擇要打開的應用程序,除非你設置了瀏覽器的一些默認行爲。
或者,你想讓客戶端自行處理各種不同的文件類型,你可以在服務器的配置文件中配置MIME類型映射,通過簡單的判斷文件後綴名來處理。例如,在Tomcat中設置MIME響應類型:
如果文件在客戶端中的響應程序類型和期望不一致,修改$TOMCAT_HOME\conf\web.xml文件中的如下部分 :
<mime-mapping>
  <extension>zip</extension>
  <mime-type>application/zip</mime-type>
</mime-mapping>
<mime-mapping>
  <extension>mht</extension>
  <mime-type>message/rfc822</mime-type>
</mime-mapping>
……

三、在響應頭中儘量不要設置瀏覽器緩存期限。
有時候用戶在點擊了下載鏈接後,在彈出窗口中,用戶想直接點擊“打開”,而不想保存到指定路徑。這時候如果我們在響應頭中限制了不允許使用瀏覽器緩存(即總是刷新),在IE瀏覽器中我們將無法直接打開該文件。因爲限制了不允許使用緩存,瀏覽器無法將文件保存到臨時文件夾(即緩存)。
也就是說,在響應頭中不要進行如下的設置(已註釋):
  //response.addHeader("pragma","NO-cache");
  //response.addHeader("Cache-Control","no-cache");
  //response.addDateHeader("Expries",0);

四、文件名爲中文或其他unicode字符時的處理。
有時候提供下載的文件名中包含中文字符或者其他unicode字符,會導致瀏覽器無法正確的採用默認的文件名保存文件。我們應該記住在響應頭中包含filename字段並採用ISO8859-1編碼(推薦)或者採用UTF-8編碼:
response.setHeader("Content-disposition","attachment; filename="+new String(filename.getBytes("UTF-8"),"iso8859-1")); //採用ISO8859-1編碼
response.setHeader("Content-disposition","attachment; filename="+URLEncoder.encode(filename, "UTF-8")); //採用UTF-8編碼
但是,這種方式在不同的瀏覽器中表現也有所不同。例如在IE和Firefox中,採用ISO8859-1編碼可以正確顯示文件名,而在Opera中不管採用那種編碼,默認保存的文件名都無法做到正確顯示。
所以最好的方法其實就是儘量在文件名中使用ascii編碼。

五、由於採用流的方式進行輸入輸出,我們必須保證在使用完畢後關閉流的資源。
一般我們把關閉流的操作放在finally塊中,以保證在程序段結束前一定會關閉流的資源:

InputStream is = null;
ServletOutputStream sos = null;
try {
  is = ...; //通過某種方式讀進數據到輸入流
  sos = response.getOutputStream(); //打開輸入流
  byte[] buff = new byte[2048];
  int bytesRead;
  while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
  sos.write(buff,0,bytesRead);
  sos.flush();
  }
} catch(IOException ex) {
  //TODO something with IOException
} catch(Exception ex) {
  //TODO something with Exception
} finally {
  if(is != null) {
  is.close(); //關閉輸入流
  }
  if(sos != null) {
  sos.close(); //關閉輸入流
  }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章