本篇来学习响应对象中一个案例场景,下载文件。就是打开浏览器,发送请求,就触发文件保存到本地的效果。场景分析,为了演示下载文件,我随便找到一个图片,命名问J2EE图片.jpn并且放在Eclipse项目的src路径下。
1.需求分析
来分析一下这个需求,图片是放在src路径下,部署到tomcat服务器之后就是在WEB-INF/classes/J2EE图片.jpg。图片文件不像文本文件,所以我们需要通过字节流方式去读取。可以同文件绝对路径得到一个输入流对象,然后写一个输出流对象,使用循环去执行输出流的输出操作。所以,大概的步骤如下
1)通过文件路径得到输入流
2)创建输出流对象
3)执行输出操作
2.代码初步实现
根据上面思路,我们写得代码如下
package com.anthony.servlet;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过文件路径得到一个输入流
String path = this.getServletContext().getRealPath("/WEB-INF/classes/J2EE图片.jpg");
FileInputStream fis = new FileInputStream(path);
//创建字节输出流,这里我们使用Servlet的输出流
ServletOutputStream sos = response.getOutputStream();
//执行输出操作
int len = 1;
byte[] b = new byte[1024]; //创建一个字节数组
while( (len = fis.read(b)) != -1) {
sos.write(b, 0, len);
}
sos.close();
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
部署测试之后,发现图片文件在浏览器显示,但是没有触发文件下载保存操作。我们代码只是输出到了浏览器,并没有告诉浏览器去下载文件,所以,需要添加告诉客户端下载文件的代码。
3.告诉客户端下载文件
通过设置响应头的内容,告诉客户端去执行下载文件操作。
package com.anthony.servlet;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过文件路径得到一个输入流
String path = this.getServletContext().getRealPath("/WEB-INF/classes/J2EE图片.jpg");
FileInputStream fis = new FileInputStream(path);
//创建字节输出流,这里我们使用Servlet的输出流
ServletOutputStream sos = response.getOutputStream();
//得到要下载文件的文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
System.out.println(filename);
//告诉客户端下载文件
response.setHeader("content-disposition" ,"attachment; filename=" + filename);
response.setHeader("content-type", "image/jpeg"); // 内容类型是 jpg的图片
//执行输出操作
int len = 1;
byte[] b = new byte[1024]; //创建一个字节数组
while( (len = fis.read(b)) != -1) {
sos.write(b, 0, len);
}
sos.close();
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
这里先得到文件的文件名,然后告诉浏览器下载文件的默认文件名就是我们得到的“J2EE图片.jpg”,执行效果
从上面下载弹窗可以看到,中文图片二字没有正常显示出来。
4.文件路径编码问题解决
这里来解决文件名称乱码的问题,文件名称得到的时候就是乱码,下面来解决filename乱码。
package com.anthony.servlet;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过文件路径得到一个输入流
String path = this.getServletContext().getRealPath("/WEB-INF/classes/J2EE图片.jpg");
FileInputStream fis = new FileInputStream(path);
//创建字节输出流,这里我们使用Servlet的输出流
ServletOutputStream sos = response.getOutputStream();
//得到要下载文件的文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
//解决路径乱码问题
filename = URLEncoder.encode(filename, "UTF-8");
System.out.println(filename);
//告诉客户端下载文件
response.setHeader("content-disposition" ,"attachment; filename=" + filename);
response.setHeader("content-type", "image/jpeg"); // 内容类型是 jpg的图片
//执行输出操作
int len = 1;
byte[] b = new byte[1024]; //创建一个字节数组
while( (len = fis.read(b)) != -1) {
sos.write(b, 0, len);
}
sos.close();
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
部署之后,IE浏览器打开效果没问题,文件名称正常显示
但是,到了火狐浏览器,文件名称没有乱码,但是显示了url的编码效果。
这个火狐浏览器的问题,开发经常犯这个错误,具体解决办法,在后面解决乱码中学习。