首先轉貼注意事項:
在論壇里,已經(jīng)有先進(jìn)說(shuō)明過(guò)如何在 Servlet / JSP 中,利用 HTTP Protocol 實(shí)作動(dòng)態(tài)的檔案下載服務(wù)。這一項功能個(gè)人在系統開(kāi)發(fā)中,用的很多,也遇到過(guò)幾個(gè)問(wèn)題,想將這些經(jīng)驗分享給大家,希望對大家能有幫助。
1. MS IE 版本的問(wèn)題
if (request.getHeader("User-Agent").indexOf("MSIE 5.5") != -1) {
// MS IE5.5 有要作特別處理
response.setHeader("Content-Disposition","filename="
+ new String( f_name.getBytes("Big5"), "ISO8859_1" ) );
}
else {
// 非 IE5.5 的 Header 設定方式
response.addHeader( "Content-Disposition", "attachment;filename="
+ new String( f_name.getBytes("Big5"), "ISO8859_1" ) );
}
IE 5.5 不能加上 attachment 這個(gè)關(guān)鍵詞,這是很奇怪的一個(gè)版本。
2. 下載中文文件名,如前程序區塊中的語(yǔ)法,其實(shí)很簡(jiǎn)單就可以作到,只要將檔名改成 "ISO8859_1" 的編碼就可以,我測過(guò)Tomcat , Oracle 9ias, Sun One 都可以正常的下載中文檔名,而且,這樣寫(xiě)法,好處是無(wú)需外加任何的 package。
3. 檔案下載完畢之后,最好加上以下這二行指令:
response.setStatus( response.SC_OK );
response.flushBuffer();
以前沒(méi)有加這二行,常??梢栽?error.log 里看到 "Connection rest by peer "這樣的錯誤訊息,而且,更嚴重的是執行下載的 servlet / jsp 不會(huì )結束,要等相當長(cháng)的時(shí)間才會(huì )Timeout,如果下載的次數一多,AP Server 就慘了,所以,有作動(dòng)態(tài)下載檔案的程序,最好還是加上這二行指令。
4. 安全性考慮,有時(shí)候寫(xiě)程序偷懶,會(huì )采用 dumpfile.jsp?f_name=attach/a.txt這樣的方式來(lái)處理檔案下載。如果,在程序中沒(méi)有過(guò)濾掉上傳文件名稱(chēng)參數中,不可夾雜 ".." 的話(huà),試想,如果有人故意將參數改成這樣呢 ?dumpfile.jsp?f_name=../../../a.txt,嘿嘿嘿,整個(gè)系統的所有檔案就任人下載啦。
以上,都是個(gè)人曾經(jīng)犯過(guò)的錯誤,給大家參考。
以前沒(méi)有加這二行,常??梢栽?error.log 里看到 "Connection rest by peer "這樣的錯誤訊息,而且,更嚴重的是執行下載的 servlet / jsp 不會(huì )結束,要等相當長(cháng)的時(shí)間才會(huì )Timeout,如果下載的次數一多,AP Server 就慘了,所以,有作動(dòng)態(tài)下載檔案的程序,最好還是加上這二行指令。
5. 安全性考慮,有時(shí)候寫(xiě)程序偷懶,會(huì )采用 dumpfile.jsp?f_name=attach/a.txt這樣的方式來(lái)處理檔案下載。如果,在程序中沒(méi)有過(guò)濾掉上傳文件名稱(chēng)參數中,不可夾雜 ".." 的話(huà),試想,如果有人故意將參數改成這樣呢 ?dumpfile.jsp?f_name=../../../a.txt,嘿嘿嘿,整個(gè)系統的所有檔案就任人下載啦。
以上,都是個(gè)人曾經(jīng)犯過(guò)的錯誤,給大家參考。
網(wǎng)址是:http://www.javaworld.com.tw/jute/post/view?bid=6&id=44580&sty=1&tpg=1&age=-1
另外一片參考文章:http://www.chinaitpower.com/A/2005-04-06/113085.html
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Download extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
try
{
//這里你可以做些其他的事情
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"你要在保存窗口中顯示的保存文件名\"");
ServletOutputStream out = response.getOutputStream();
BufferedReader br=new BufferedReader(new FileReader(要下載的的文件名));
String line=br.readLine();
while (line!=null)
{
out.write(line.getBytes());
out.println();
line=br.readLine();
}
out.close();
br.close();
}
catch (Exception e)
{
System.out.println(e);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
doGet(request, response);
}
}
注意:中文文件名解決辦法, 將第一個(gè)引用中的 BIG5 改為 GBK 即可:
new String(name.getBytes("GBK"), "ISO8859_1")
上面下載代碼中有個(gè)問(wèn)題, 只能下載字符類(lèi)文件,對于二進(jìn)制的文件會(huì )出錯, 應改用下面代碼
BufferedInputStream in = null;
ServletOutputStream out = null;
FileInputStream stream = null;
try {
out = response.getOutputStream();
stream = new FileInputStream(file);
int bytesRead = 0;
final int length = 8192;
byte[] buffer = new byte[length];
while ((bytesRead = stream.read(buffer, 0, length)) != -1) {
// write at server side
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
throw new BPDBusiException(
ResourceConst.SCORECARD_ERR_DOWNLOADATTACHMENT_DOWNLOAD);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
聯(lián)系客服