檔案下載本質是「伺服器將檔案轉為輸出流 → 瀏覽器接收流 → 提示另存」。根據業務需求(權限控制、大檔支援、斷點續傳),可選擇四種方案。
<a href="/files/report.pdf">下載報表</a>
<%@ page import="java.io.*" %>
<%
String filepath = "E:/data/report.pdf";
File file = new File(filepath);
String filename = URLEncoder.encode(file.getName(), "UTF-8");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
response.setContentLengthLong(file.length());
try (InputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream()) {
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
}
%>
Content-Disposition: attachment 強制下載;Content-Length 支援進度條。response.setBufferSize(0) 關閉緩衝,避免 OOM。@GetMapping("/download/{id}")
public ResponseEntity<Resource> download(@PathVariable Long id, HttpServletRequest req) {
File file = storageService.getFile(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encode(file.getName()) + "\"")
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new FileSystemResource(file)); // Spring 自動使用零拷貝 FileChannel
}
FileChannel.transferTo)、自動支援 Range 請求(斷點續傳)、整合權限攔截器。X-Accel-Redirect / Apache mod_xsendfile 可進一步卸載靜態檔傳輸給 Web Server。| 場景 | 推薦方案 |
|---|---|
| 公開靜態資源、大檔、高併發 | Nginx X-Accel-Redirect / 直接連結 + CDN |
| 需權限、動態生成、中小檔 | Servlet/JSP 流式輸出或 Spring MVC Resource |
| 需斷點續傳、超大檔(>1GB) | 支援 Range 的 Controller + 對象存儲簽名 URL |
核心原則:業務邏輯(權限/統計)走 Java,資料傳輸(IO/頻寬)交給 Web Server/對象存儲。