文件下载案例(Servlet)
文件下载是 Java Web 开发中的常见需求,其本质是:
服务器以“附件”的形式将文件内容通过响应流返回给浏览器。
一、实现思路概述
整体流程如下:
- 浏览器通过超链接向服务器发送请求,并携带文件名参数
- Servlet 接收请求,获取文件名
- 通过
ServletContext获取文件在服务器中的真实路径 - 使用字节输入流读取文件内容
- 设置响应头(MIME 类型 + 下载方式)
- 将文件内容写入响应输出流,返回给浏览器
二、前端 HTML 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件下载示例</title>
</head>
<body>
<!-- 通过超链接访问 Servlet,并携带要下载的文件名 -->
<a href="/DownloadTest/downloadServlet?filename=1.jpg">点击下载图片 1</a><br>
<a href="/DownloadTest/downloadServlet?filename=2.jpg">点击下载图片 2</a><br>
<a href="/DownloadTest/downloadServlet?filename=3.jpg">点击下载图片 3</a><br>
</body>
</html>
说明
href指向下载 Servlet 的访问路径filename作为请求参数,用于告知服务器要下载的具体文件- 浏览器默认会发送 GET 请求
三、Servlet 后端实现
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获取请求参数(文件名)
String filename = request.getParameter("filename");
// 2. 获取文件在服务器中的真实路径
String realPath = this.getServletContext()
.getRealPath("/img/" + filename);
// 3. 使用字节输入流读取文件
FileInputStream fis = new FileInputStream(realPath);
// 4. 设置响应头 —— MIME 类型
String mimeType = this.getServletContext().getMimeType(filename);
response.setContentType(mimeType);
// 5. 设置响应头 —— 下载方式(附件形式)
response.setHeader(
"Content-Disposition",
"attachment;filename=" + filename
);
// 6. 将文件内容写入响应输出流
ServletOutputStream sos = response.getOutputStream();
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = fis.read(buffer)) != -1) {
sos.write(buffer, 0, len);
}
// 7. 释放资源
fis.close();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// GET 请求统一交由 POST 处理
this.doPost(request, response);
}
}
四、关键点解析
1. 文件真实路径获取
getServletContext().getRealPath("/img/" + filename);
/img是 Web 项目中的资源目录getRealPath()可将虚拟路径转换为服务器磁盘路径
2. MIME 类型设置
String mimeType = getServletContext().getMimeType(filename);
response.setContentType(mimeType);
- 不同文件类型需要对应的 MIME 类型
- 由服务器自动判断,避免手动维护
3. Content-Disposition 响应头
response.setHeader(
"Content-Disposition",
"attachment;filename=" + filename
);
作用:
attachment:以附件形式下载,而不是直接在浏览器中打开filename:指定下载时的默认文件名
4. 字节流传输文件
- 文件下载必须使用 字节流
- 不能使用字符流(会导致二进制文件损坏)
五、常见问题与优化建议
1. 中文文件名乱码问题
在实际项目中,中文文件名需要进行编码处理,例如:
filename = URLEncoder.encode(filename, "UTF-8");
2. 大文件下载
- 采用缓冲区(已使用)
- 避免一次性加载整个文件到内存
3. 安全性问题
- 校验
filename,防止路径穿越攻击 - 限制可下载目录范围