需求
1.页面显示超链接 2.点击超链接后弹出下载对话框 3.完成图片文件下载
分析
超链接指向的资源如果能够被浏览器解析,则直接在浏览器中展示,如果不能解析,则弹出下载提示框。如果希望无论返回什么资源都不要解析,而是让用户下载,那么就必须使用 content-disposition 响应头告诉客户端,返回的资源(响应体的数据)以附件的形式打开。
实现步骤
1.开发前端页面,使用超链接标签,href 属性指向一个 Servlet,并且传递下载资源的名称 2.实现后端逻辑,定义一个 Servlet,获取下载资源的名称,再根据资源名称将对应的资源加载入内存中,再从内存输出到 Response对象中,再返回给客户端 2.1.获取参数 2.2.使用字节输入流读取资源文件,加载进内存中 2.3.设置响应头(content-type 和 content-disposition) 2.4.使用字节输出流写入到 Response 对象中。具体是从内存写入到 Response 的字节输出流中,再从字节输出流写入到 Response 对象中 2.5.服务器从 Response 对象中获取数据构建成响应报文发送给客户端(这步服务器自动完成)
说明:
response.setHeader("content-disposition", "attachement;filename=123.jpeg");
上述代码表示将响应头 content-disposition 的值设为 attachement;filename=123.jpeg。其中 attachement 表示响应的资源以附件形式打开;filename 是弹出的下载对话框中显示的文件名称以及文件下载后的文件名称。
示例代码
前端页面示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/servlet_demo/download?fileName=1.jpeg">图片</a>
<a href="/servlet_demo/download?fileName=1.avi">视频</a>
</body>
</html>
服务端示例代码:
package priv.lwx.javaex.servlet_demo.web.servlet.download;
import javax.servlet.ServletContext;
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("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileName = request.getParameter("fileName");
String realPath = this.getServletContext().getRealPath("/image/" + fileName);
FileInputStream fis = new FileInputStream(realPath);
System.out.println(fis);
ServletContext context = this.getServletContext();
String mimeType = context.getMimeType(fileName);
response.setHeader("content-type", mimeType);
response.setHeader("content-disposition", "attachement;filename=" + fileName);
ServletOutputStream sos = response.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len = 0;
while ((len = fis.read(buff)) != -1) {
sos.write(buff, 0, len);
}
fis.close();
}
}
下载的文件中文名显示问题
如果你下载的文件名称是中文,不同浏览器版本会有不同的显示,不过都是错误的显示。
解决的办法:判断浏览器的版本,根据不同的浏览器版本对文件名进行不同的编码,再返回给客户端显示。
处理文件名称的示例代码如下:
package priv.lwx.javaex.servlet_demo.util;
import Decoder.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownloadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException, UnsupportedEncodingException {
if (agent.contains("М?IЕ")) {
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
最终完整的文件下载的示例代码:
package priv.lwx.javaex.servlet_demo.web.servlet.download;
import priv.lwx.javaex.servlet_demo.util.DownloadUtils;
import javax.servlet.ServletContext;
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("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileName = request.getParameter("fileName");
String realPath = this.getServletContext().getRealPath("/image/" + fileName);
FileInputStream fis = new FileInputStream(realPath);
ServletContext context = this.getServletContext();
String mimeType = context.getMimeType(fileName);
response.setHeader("content-type", mimeType);
response.setHeader("content-disposition", "attachement;filename=" + fileName);
ServletOutputStream sos = response.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len = 0;
while ((len = fis.read(buff)) != -1) {
sos.write(buff, 0, len);
}
fis.close();
}
}
|