理解和靈活應用 Struts2 的文件下載功能
文件下載給我們最直接的概念就是,給個文件鏈接點擊就下載。似乎太簡單,然而 Struts2 卻把它作爲一個獨立的學問來對待,理由有四:
1. 文件名爲中文時,直接點擊下載,鏈接可能會走樣(某些瀏覽器,URL 編碼的問題),致使無法下載。
2. 不總是從下載實際的文件,文件內容有時候是動態生成的,如數據庫中的內容。
3. 對於知名的文件類型不讓瀏覽器直接打開,而是出現下載對話框保存文件。例如,要下載的文件是 .txt 的,可能直接就在瀏覽器中顯示其內容。
4. 需要授權才能下載文件時
當然對於以上若干問題,Servlet/JSP 都能通過正確的 URL 編碼,響應頭設置、權限代碼控制解決,只是 Struts2 讓我們處理起來更方便了,內部原理自然是一樣的。
先來看下 Servlet 如何實現文件下載的,直接見代碼:
view sourceprint?01.PrintWriter out = response.getWriter();
02.
03.//不管實際類型,待下載文件 ContentType 統一指定爲 application/octet-stream
04.response.setContentType("application/octet-stream");
05.
06.//中文文件名必須轉碼爲 ISO8859-1,否則爲亂碼
07.String fileName = new String("文本文件.txt".getBytes(), "ISO8859-1");
08.
09.//作爲附件下載,相應的 "inline;filename = "+fileName 是在線(瀏覽器中顯示內容)打開
10.response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
11.
12.//因爲文件編碼也爲 ISO8859-1,所以內容須轉碼成 ISO8859-1,尚不知如何控制下載文本文件的編碼
13.//或有誰知道的,還請告訴我一下。 文件內容可以從物理文件中來,或者數據庫中讀取填入等等
14.out.write(new String("Servlet 文件下載測試".getBytes(), "ISO8859-1"));
15.
16.out.close();
知道了上面各行的含義,再來看下 Struts2 的解決方式,其實不過是把某些代碼的功能移入到了配置文件而已。在李剛所著的《Struts 2 權威指南》中說 Struts 實現文件下載是由一個 download 攔截器。其實不然,只是一個 StreamResult(org.apache.struts2.dispatcher.StreamResult) 而已,也不像實現文件上傳那樣要額外的 JAR 包。在 StreamResult 中有以下幾個默認屬性要留意一下:
public static final String DEFAULT_PARAM = "inputName";
protected String contentType = "text/plain";
protected String contentDisposition = "inline";
protected String inputName = "inputStream";
protected InputStream inputStream;
protected int bufferSize = 1024;
StreamResult 的實現細節敬請閱讀它的源代碼,實現過程一言以蔽之就是:從 inputStream 獲取內容,以相應的 contentType、contentDisposition 和 bufferSize 輸出給瀏覽器,對 contentType 和 contentDisposition 的相應設置就能實現文件下載,可對照前面 Servlet 的實現。看個實際的例子吧。
struts.xml 中 Action 的配置,假定 Action 類爲 com.unmi.DownLoadAction
view sourceprint?01.
02.
03.
application/octet-stream
04.
05.
07.
inputStream
08.
09.
12.
attachment;filename="${fileName}"
13.
4096
14.
說明:對於上面的配置其他參數可以用默認值,關鍵就是 contentDisposition 要設置爲 attachment 才能提示下載,同時用 filename 指定文件名,若直接指定非動態的文件名。
DownloadAction 代碼,需要實現 getInputStream() 返回輸入流;因前面用的動態文件名,所以須加上 getFileName() 返回文件名,若非動態文件名,則該方法可省去。
view sourceprint?01.package com.unmi.action;
02.
03.import java.io.*;
04.import java.text.*;
05.import java.util.Date;
06.
07./**
08.
* 文件下載的 Action
09.
* @author Unmi
10.
*/
11.public class NetbookSerialAction {
12.
13.
public String execute() throws Exception {
14.
//這裏可加入權限控制
15.
return "success";
16.
}
17.
18.
//獲得下載文件的內容,可以直接讀入一個物理文件或從數據庫中獲取內容
19.
public InputStream getInputStream() throws Exception {
20.
//return new FileInputStream("somefile.rar"); 直接下載 somefile.rar
21.
22.
//和 Servlet 中不一樣,這裏我們不需對輸出的中文轉碼爲 ISO8859-1
23.
return new ByteArrayInputStream("Struts2 文件下載測試".getBytes());
24.
}
25.
26.
//對於配置中的 ${fileName}, 獲得下載保存時的文件名
27.
public String getFileName() {
28.
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
29.
String fileName = "序列號(" + df.format(new Date()) + ").txt";
30.
try {
31.
//中文文件名也是需要轉碼爲 ISO8859-1,否則亂碼
32.
return new String(fileName.getBytes(), "ISO8859-1");
33.
} catch (UnsupportedEncodingException e) {
34.
return "impossible.txt";
35.
}
36.
}
37.}
謹記一個就是,要想下載的文件名不亂碼就要以 ISO8859-1 字符集進行轉碼,內容會否亂碼可在調試中解決。
好啦,啓動服務,訪問 http://localhost:8080/teststruts2/download.action,瀏覽器便會提示下載 序列號(2009-06-17).txt,內容爲:“Struts2 文件下載測試”。
參考:1. 淺談Struts2下載文件的方法實現
2. struts2多文件動態下載及中文解決方案
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.