<%-- 直接在JSP頁面中進行檔案下載的代碼(改 Servlet 或者 JavaBean 的話自己改吧), 支援中文附件名(做了轉內碼處理). 事實上只要向 out 輸出位元組就被認為是附件內容, 不一定非要從檔案讀取未經處理資料, 從資料 庫中讀取也可以的. 需傳三個參數 newname,name,path --%> <%@ page contentType=" text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="java.io.*,java.util.*,java.text.*"%> <%!//If returns true, then should return a 304 (HTTP_NOT_MODIFIED) public static boolean checkFor304(HttpServletRequest req, File file) { // We'll do some handling for CONDITIONAL GET (and return a 304) // If the client has set the following headers, do not try for a 304. // pragma: no-cache // cache-control: no-cache if ("no-cache".equalsIgnoreCase(req.getHeader("Pragma")) || "no-cache".equalsIgnoreCase(req.getHeader("cache-control"))) { // Wants specifically a fresh copy } else { // HTTP 1.1 ETags go first String thisTag = Long.toString(file.lastModified()); String eTag = req.getHeader("If-None-Match"); if (eTag != null) { if (eTag.equals(thisTag)) { return true; } } // Next, try if-modified-since DateFormat rfcDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); Date lastModified = new Date(file.lastModified()); try { long ifModifiedSince = req.getDateHeader("If-Modified-Since"); // log.info("ifModifiedSince:"+ifModifiedSince); if (ifModifiedSince != -1) { long lastModifiedTime = lastModified.getTime(); // log.info("lastModifiedTime:" + lastModifiedTime); if (lastModifiedTime <= ifModifiedSince) { return true; } } else { try { String s = req.getHeader(" If-Modified-Since "); if (s != null) { Date ifModifiedSinceDate = rfcDateFormat.parse(s); // log.info("ifModifiedSinceDate:" + ifModifiedSinceDate); if (lastModified.before(ifModifiedSinceDate)) { return true; } } } catch (ParseException e) { // log.warn(e.getLocalizedMessage(), e); } } } catch (IllegalArgumentException e) { // Illegal date/time header format. // We fail quietly, and return false. // FIXME: Should really move to ETags. } } return false; }%> <% String newname=request.getParameter("upfile_newname"); String name=request.getParameter("upfile_name"); String path=request.getParameter("upfile_path"); // String filePath = "c:/文檔.doc"; // 如果是 WEB APP 下的相對路徑檔案, 請使用下列代碼: if(path.charAt(0)=='/') path=path.substring(1); String filePath = application.getRealPath(path+"/"+newname); boolean isInline = false; // 是否允許直接在瀏覽器內開啟(如果瀏覽器能夠預覽此檔案內容, // 那麼檔案將被開啟, 否則會提示下載) // 清空緩衝區, 防止頁面中的空行, 空格添加到要下載的檔案內容中去 // 如果不清空的話在調用 response.reset() 的時候 Tomcat 會報錯 // java.lang.IllegalStateException: getOutputStream() has already been called for // this response, out.clear(); // {{{ BEA Weblogic 必讀 // 修正 Bea Weblogic 出現 "getOutputStream() has already been called for this response"錯誤的問題 // 關於檔案下載時採用檔案流輸出的方式處理: // 加上response.reset(),並且所有的%>後面不要換行,包括最後一個; // 因為Application Server在處理編譯jsp時對於%>和<%之間的內容一般是原樣輸出,而且預設是PrintWriter, // 而你卻要進行流輸出:ServletOutputStream,這樣做相當於試圖在Servlet中使用兩種輸出機制, // 就會發生:getOutputStream() has already been called for this response的錯誤 // 詳細請見《More Java Pitfill》一書的第二部分 Web層Item 33:試圖在Servlet中使用兩種輸出機制 270 // 而且如果有換行,對於文字檔沒有什麼問題,但是對於其它格式,比如AutoCAD、Word、Excel等檔案 // 下載下來的檔案中就會多出一些分行符號0x0d和0x0a,這樣可能導致某些格式的檔案無法開啟,有些也可以正常開啟。 // 同時這種方式也能清空緩衝區, 防止頁面中的空行等輸出到下載內容裡去 response.reset(); // }}} try { java.io.File f = new java.io.File(filePath); if (f.exists() && f.canRead()) { // 我們要檢查用戶端的緩衝中是否已經有了此檔案的最新版本, 這時候就告訴 // 用戶端無需重新下載了, 當然如果不想檢查也沒有關係 if (checkFor304(request, f)) { // 用戶端已經有了最新版本, 返回 304 response.sendError(HttpServletResponse.SC_NOT_MODIFIED); return; } // 從伺服器的配置來讀取檔案的 contentType 並設定此contentType, 不推薦設定為 // application/x-download, 因為有時候我們的客戶可能會希望在瀏覽器裡直接開啟, // 如 Excel 報表, 而且 application/x-download 也不是一個標準的 mime type, // 似乎 FireFox 就不認識這種格式的 mime type String mimetype = null; mimetype = application.getMimeType(filePath); if (mimetype == null) { mimetype = "application/octet-stream;charset=iso8859-1"; } response.setContentType(mimetype); // IE 的話就只能用 IE 才認識的頭才能下載 HTML 檔案, 否則 IE 必定要開啟此檔案! String ua = request.getHeader("User-Agent"); // 擷取終端類型 if (ua == null) ua = "User-Agent:Mozilla/4.0(compatible; MSIE 6.0;)"; boolean isIE = ua.toLowerCase().indexOf("msie") != -1; // 是否為 IE if (isIE && !isInline) { mimetype = "application/x-msdownload"; } // 下面我們將設法讓用戶端儲存檔案的時候顯示正確的檔案名稱, 具體就是將檔案名稱 // 轉換為 ISO8859-1 編碼 String downFileName = new String(f.getName().getBytes(),"iso8859-1"); String inlineType = isInline ? "inline" : "attachment"; // 是否內聯附件 // or using this, but this header might not supported by FireFox // response.setContentType("application/x-download"); response.setHeader("Content-Disposition", inlineType+";filename=""+name+"""); response.setContentLength((int) f.length()); // 設定下載內容大小 byte[] buffer = new byte[4096]; // 緩衝區 BufferedOutputStream output = null; BufferedInputStream input = null; try { output = new BufferedOutputStream(response.getOutputStream()); input = new BufferedInputStream(new FileInputStream(f)); int n = (-1); while ((n = input.read(buffer, 0, 4096)) > -1) { output.write(buffer, 0, n); } <SPAN style="COLOR: #ff00ff">response.flushBuffer();//明白了,如何下載內容</SPAN> } catch (Exception e) { } // 使用者可能取消了下載 finally { if (input != null) input.close(); if (output != null) output.close(); } } return; } catch (Exception ex) { ex.printStackTrace(); } // 如果下載失敗了就告訴使用者此檔案不存在 response.sendError(404); %> |