會員註冊 / 登入  |  電腦版  |  Jump to bottom of page

網頁程式設計 Web Development » JSP精選實用範例(三):檔案下載

發表人: andowson, 七段學員
2007-12-16 21:23:45
要被下載的檔案先寫入到一個特定的目錄下如/WEB-INF/export,然後呼叫download.jsp?file=targetFileName取得,下載後並將檔案刪除。
程式碼:
download.jsp

<%@ page import= "java.io.*" %>
<%!
private static final int BUFSIZE = 2048;
/**
* Sends a file to the ServletResponse output stream. Typically
* you want the browser to receive a different name than the
* name the file has been saved in your local database, since
* your local names need to be unique.
*
* @param request The request
* @param response The response
* @param filename The name of the file you want to download.
* @param original_filename The name the browser should receive.
*/
private void doDownload( HttpServletRequest request, HttpServletResponse response,
String filename, String original_filename )
throws IOException
{
File f = new File(filename);
int length = 0;
ServletOutputStream op = response.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType( filename );

//
// Set the response and go!
//
//
response.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
response.setContentLength( (int)f.length() );
response.setHeader( "Content-Disposition", "attachment; filename=\"" + original_filename + "\"" );

//
// Stream to the requester.
//
byte[] bbuf = new byte[BUFSIZE];
DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1))
{
op.write(bbuf,0,length);
}

in.close();
op.flush();
op.close();
}
%>
<%
String original_filename = request.getParameter("file");
// Security Isuue: User can type file=../WEB-INF/web.xml
//String filename = application.getRealPath(original_filename);
boolean error = false;
if (original_filename != null && !"".equals(original_filename) && !original_filename.startsWith("../")) {
String filename = application.getRealPath("/")+"WEB-INF/export/" + original_filename;
File file = new File(filename);
if (file.exists()) {
doDownload(request, response, filename, original_filename);
// delete the file after download
boolean deleted = file.delete();
System.out.println("File " + original_filename + " deleted: " + deleted);
} else {
error = true;
}
} else {
error = true;
}
if (error) {
response.setContentType("text/html; charset=UTF-8");
out.println("File not found: " + original_filename);
}
%>

參考資料:
http://www.jspwiki.org/wiki/MakingADownloadServlet

檔案名稱 download.jsp
描述 檔案下載程式
檔案大小 3 Kbytes
下載次數 186 次
[Disk] 下載


發表人: lionsgogo, 十級學員
2010-03-08 21:33:30
我有在WEB-INF/export建立一個資料夾

但是好像找不到檔案

出現"File not found: null"

是怎麼回事?

發表人: andowson, 七段學員
2010-03-09 08:21:21
lionsgogo您好:
您應該是直接打download.jsp這樣子去執行吧?正確的使用方式是需要提供一個參數file來指定要下載的檔案名稱(位於WEB-INF/export目錄下),例如:download.jsp?file=test.csv

發表人: mylipton, 十級學員
2010-06-08 15:04:09
andowson您好
這範例程式如果下載中文檔名的檔案會有問題,自己試了一些方法,還是不成功
請問您有辦法可以讓他下載中文檔名的檔案嗎

發表人: andowson, 七段學員
2010-06-08 18:01:49
mylipton您好:
要下載中文檔名的檔案也很簡單,只要將傳數的參數加以轉換編碼即可。

<%@ page import= "java.io.*" %>
<%!
private static final int BUFSIZE = 2048;
/**
* Sends a file to the ServletResponse output stream. Typically
* you want the browser to receive a different name than the
* name the file has been saved in your local database, since
* your local names need to be unique.
*
* @param request The request
* @param response The response
* @param filename The name of the file you want to download.
* @param original_filename The name the browser should receive.
*/
private void doDownload( HttpServletRequest request, HttpServletResponse response,
String filename, String original_filename )
throws IOException
{
File f = new File(filename);
int length = 0;
ServletOutputStream op = response.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType( filename );

//
// Set the response and go!
//
//
response.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
response.setContentLength( (int)f.length() );
response.setHeader( "Content-Disposition", "attachment; filename=\"" + original_filename + "\"" );

//
// Stream to the requester.
//
byte[] bbuf = new byte[BUFSIZE];
DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1))
{
op.write(bbuf,0,length);
}

in.close();
op.flush();
op.close();
}
%>
<%
String original_filename = request.getParameter("file");
String target_filename = "";

// Security Isuue: User can type file=../WEB-INF/web.xml
//String filename = application.getRealPath(original_filename);
boolean error = false;
if (original_filename != null && !"".equals(original_filename.trim()) && !original_filename.startsWith("../")) {
target_filename = new String(original_filename.getBytes("ISO-8859-1"), "MS950");
String filename = application.getRealPath("/")+"WEB-INF/export/" + target_filename;
File file = new File(filename);
if (file.exists()) {
doDownload(request, response, filename, original_filename);
// delete the file after download
//boolean deleted = file.delete();
//System.out.println("File " + target_filename + " deleted: " + deleted);
} else {
error = true;
}
} else {
error = true;
}
if (error) {
response.setContentType("text/html; charset=MS950");
out.println("File not found: " + target_filename);
}
%>

檔案名稱 download.jsp
描述 支援中文檔名下載
檔案大小 3 Kbytes
下載次數 36 次
[Disk] 下載


發表人: mylipton, 十級學員
2010-06-09 14:55:09
andowson您好
我試過你放的程式了,還是會因為中文變亂碼的問題而找不到檔案
我也試過一些編碼的設定
也是無法成功

發表人: mylipton, 十級學員
2010-06-09 17:51:42
andowson 您好
我把ISO-88591-1 後面的UTF-8 改成big5之後可以下載中文檔名的檔案了,
但很奇怪,如果我把路徑"/WEB-INF/export" 改成別的路徑,就又會出現File not found

發表人: andowson, 七段學員
2010-06-09 17:56:09
mylipton您好:
我今天測試了一下,發現不同的瀏覽器對於中文檔名直接輸入在網址列的處理有點不同,Google Chrome會自動把中文字改為UTF-8編碼,IE和Firefox則不會。
以下是我的測試方法,供您參考:
1.在WEB-INF/export目錄下手動產生一個文字檔,名稱就叫做「新增文字文件.txt」
2.在網址列上直接輸入:
http://localhost:8080/examples/download.jsp?file=新增文字文件.txt
修改後的程式碼如下:

<%@ page import= "java.io.*" %>
<%!
private static final int BUFSIZE = 2048;
/**
* Sends a file to the ServletResponse output stream. Typically
* you want the browser to receive a different name than the
* name the file has been saved in your local database, since
* your local names need to be unique.
*
* @param request The request
* @param response The response
* @param filename The name of the file you want to download.
* @param original_filename The name the browser should receive.
*/
private void doDownload( HttpServletRequest request, HttpServletResponse response,
String filename, String original_filename )
throws IOException
{
File f = new File(filename);
int length = 0;
ServletOutputStream op = response.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType( filename );

//
// Set the response and go!
//
//
response.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
response.setContentLength( (int)f.length() );
response.setHeader( "Content-Disposition", "attachment; filename=\"" + original_filename + "\"" );

//
// Stream to the requester.
//
byte[] bbuf = new byte[BUFSIZE];
DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1))
{
op.write(bbuf,0,length);
}

in.close();
op.flush();
op.close();
}
%>
<%
String original_filename = request.getParameter("file");
String target_filename = "";

// Chrome will auto escape the URL characters
String userAgent = request.getHeader("user-agent");
System.out.println(userAgent);
String charset = "MS950";
if (userAgent.indexOf("Chrome") != -1) {
charset = "UTF-8";
}

// Security Isuue: User can type file=../WEB-INF/web.xml
//String filename = application.getRealPath(original_filename);
boolean error = false;
if (original_filename != null && !"".equals(original_filename.trim()) && !original_filename.startsWith("../")) {
target_filename = new String(original_filename.getBytes("ISO-8859-1"), charset);
String filename = application.getRealPath("/")+"WEB-INF/export/" + target_filename;
File file = new File(filename);
if (file.exists()) {
doDownload(request, response, filename, original_filename);
// delete the file after download
//boolean deleted = file.delete();
//System.out.println("File " + target_filename + " deleted: " + deleted);
} else {
error = true;
}
} else {
error = true;
}
if (error) {
response.setContentType("text/html; charset=UTF-8");
out.println("File not found: " + target_filename);
}
%>

檔案名稱 download.jsp
描述 修正後的檔案下載程式
檔案大小 3 Kbytes
下載次數 35 次
[Disk] 下載


發表人: andowson, 七段學員
2010-06-09 18:05:27
 
mylipton wrote:andowson 您好
我把ISO-88591-1 後面的UTF-8 改成big5之後可以下載中文檔名的檔案了,
但很奇怪,如果我把路徑"/WEB-INF/export" 改成別的路徑,就又會出現File not found

這是設計上的問題,這個下載程式為了安全起見,將所要要下載的檔案都放在WEB-INF/export目錄下,您可以配合需要更改設計。例如您可以改為將檔案都放在WEB-INF/download目錄下,則程式中就應改為WEB-INF/download。

發表人: mylipton, 十級學員
2010-06-23 14:31:57
andowson
感謝你的回答,之前的問題已經解決了
但想請問一下,如果我想把上傳檔案傳到別的槽的資料夾改怎麼作
比如我的網站是放在C槽,但傳上來的檔案我想放到D槽

發表人: andowson, 七段學員
2010-07-05 17:51:21
要避免發生java.lang.IllegalStateException: getOutputStream() has already been called for this response,可以在doDownload()後面加上下面兩行
out.clear();
out = pageContext.pushBody();
修改後的原始程式碼如下:
download.jsp

<%@ page import="java.io.*"%>
<%!
private static final int BUFSIZE = 2048;
/**
* Sends a file to the ServletResponse output stream. Typically
* you want the browser to receive a different name than the
* name the file has been saved in your local database, since
* your local names need to be unique.
*
* @param request The request
* @param response The response
* @param filename The name of the file you want to download.
* @param original_filename The name the browser should receive.
*/
private void doDownload( HttpServletRequest request, HttpServletResponse response,
String filename, String original_filename )
throws IOException
{
File f = new File(filename);
int length = 0;
ServletOutputStream op = response.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType( filename );

//
// Set the response and go!
//
//
response.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
response.setContentLength( (int)f.length() );
response.setHeader( "Content-Disposition", "attachment; filename=\"" + original_filename + "\"" );

//
// Stream to the requester.
//
byte[] bbuf = new byte[BUFSIZE];
DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1))
{
op.write(bbuf,0,length);
}

in.close();
op.flush();
op.close();
}
%>
<%
String original_filename = request.getParameter("file");
String target_filename = "";

// Chrome will auto escape the URL characters
String userAgent = request.getHeader("user-agent");
System.out.println(userAgent);
String charset = "MS950";
if (userAgent.indexOf("Chrome") != -1) {
charset = "UTF-8";
}

// Security Isuue: User can type file=../WEB-INF/web.xml
//String filename = application.getRealPath(original_filename);
boolean error = true;
if (original_filename != null && !"".equals(original_filename.trim()) && !original_filename.startsWith("../")) {
target_filename = new String(original_filename.getBytes("ISO-8859-1"), charset);
String filename = application.getRealPath("/")+"WEB-INF/export/" + target_filename;
File file = new File(filename);
if (file.exists()) {
doDownload(request, response, filename, original_filename);
// aviod java.lang.IllegalStateException: getOutputStream() has already been called for this response
out.clear();
out = pageContext.pushBody();
// delete the file after download
//boolean deleted = file.delete();
//System.out.println("File " + target_filename + " deleted: " + deleted);
error = false;
}
}
if (error) {
response.setContentType("text/html; charset=UTF-8");
out.println("File not found: " + target_filename);
}
%>

檔案名稱 download.jsp
描述 避免產生java.lang.IllegalStateException: getOutputStream() has already been called for this response
檔案大小 3 Kbytes
下載次數 92 次
[Disk] 下載


發表人: kisskevin524, 十級學員
2011-04-20 17:26:22
我想請問一下
我下載功能都正常
下載時會出現"開啟舊檔","儲存","取消"畫面
當我點選"開啟舊檔","儲存"都沒問題
但是我選擇"取消"時,tomcat後端會顯示
java.lang.IllegalStateException: getOutputStream() has already been called for this response

不知如何解決/
謝謝!!

發表人: andowson, 七段學員
2011-04-23 09:47:51
kisskevin524您好:
我用#11那篇的download.jsp在Windows Vista上跑Tomcat 7.0.12上測試,沒遇到您所說的問題,請再確認一下環境跟您使用的版本。

發表人: Siao, 十級學員
2013-01-24 14:44:00
andowson 你好,我最近在寫jsp下載時遇到一個問題。點選連結之後他不會跳出下載視窗,而是直接在原本的頁面上顯示檔案內容。我該怎麼解決呢?

發表人: Siao, 十級學員
2013-01-24 16:46:46
andowson你好我稍早所描述的問題已經解決了,不好意思打擾你了,感恩!!




會員註冊 / 登入  |  電腦版  |  Jump to top of page