在 Java Web 开发中,文件下载是常见需求。本文通过实例详细讲解两种主流实现方案:简单的超链接下载与更可控的 Servlet 流式下载,并分析浏览器对不同文件类型的处理差异。
最直观的方式是使用 HTML <a> 标签直接指向文件路径:
<a href="/day06/download/cors.zip">压缩包</a> <a href="/day06/download/1.png">图片</a>
这种方式无需后端代码,但存在明显缺陷:浏览器能识别的文件类型(如图片、PDF、TXT)会直接在浏览器中打开,而非触发下载;只有无法识别的类型(如 ZIP、RAR)才会弹出下载对话框。这导致用户体验不一致。
通过 Servlet 读取文件流并设置响应头,可强制所有文件以附件形式下载,完美解决上述问题。
<a href="/day06/ServletDownload?filename=cors.zip">压缩包</a>filenameContent-Type 为文件 MIME 类型Content-Disposition: attachment;filename=xxx 强制下载ServletContext.getRealPath() 获取服务器绝对路径FileInputStream 读取文件,response.getOutputStream() 写入响应@WebServlet("/ServletDownload")
public class ServletDownload extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filename = request.getParameter("filename");
// 设置响应头
response.setContentType(getServletContext().getMimeType(filename));
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
// 读取文件并输出
String fullPath = getServletContext().getRealPath("/download/" + filename);
try (InputStream in = new FileInputStream(fullPath);
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
}
}
实际项目中常封装工具类处理编码、大文件分块传输、断点续传等场景。关键点包括:
new String(filename.getBytes("UTF-8"), "ISO-8859-1") 解决中文乱码Content-Length 支持下载进度显示BufferedInputStream/OutputStream 提升大文件传输性能window.location.href 发起请求,AJAX 无法直接处理文件流下载超链接下载适合简单静态资源,Servlet 流式下载提供完全控制,是企业级应用的标准做法。理解浏览器 MIME 类型识别机制与 Content-Disposition 头的作用,是掌握文件下载的关键。