现在我们希望访问一个Servlet服务,从服务器上下载一个文件到本地,这可以使用HttpServletResponse进行实现,具体代码如下:
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取图片的真实路径
String path = this.getServletContext().getRealPath("/WEB-INF/classes/小狗.jpeg");
// 2. 提取文件的文件名,即真实路径最后一个斜杠后的子串
String filename = path.substring(path.lastIndexOf('/') + 1);
// 3. 设置Http响应的消息头,使图片作为附件可以被下载
// 注意:为了使得下载的文件名依然为正常的中文,必须对去按utf-8进行编码,否则会出现乱码
resp.setHeader("Content-Disposition",
"attachment; filename=\"" + URLEncoder.encode(filename, "utf-8") + "\"");
// 4. 获取文件输入流,从而可以读取二进制文件
FileInputStream inputStream = new FileInputStream(path);
// 5. 获取Http响应输出流,从而可以传输二进制文件
ServletOutputStream outputStream = resp.getOutputStream();
// 6. 创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
// 7. 将文件读入到文件输入流中,再写入Http响应输出流里
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
// 8. 关闭流
inputStream.close();
outputStream.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
上面的代码有如下几个注意点:
1. 获取文件在服务器上的真实路径:按照惯例,我们应当把文件都放在resources目录下,所以程序打包后,resources目录下的文件都会被搬运到target的应用根目录下的WEB-INF/classes目录下。所以,通过ServletContext得到RealPath时,要把路径写成“/WEB-INF/classes/XXX.XX”。
2. 支持文件名为中文的下载:假如文件名为英语,则第3步中的语句只需写成如下这样即可:
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
但是,如果文件名为英文,上面代码的执行结果为:
可以看到,文件名变成了一道下划线,也就是说文件名字符串出现了乱码。要解决这个问题,就必须对filename进行UTF-8编码,即通过URLEncoder.encode实现。