web 应用常用功能文件下载
文件下载的原理分析图
● 文件下载原理分析图
代码应用实例
● 需求:演示文件下载,如图
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件下载</title> <base href="<%=request.getContextPath()+"/"%>>"> </head> <body> <h1>文件下载</h1> <a href="fileDownLoadServlet?name=1.jpg">点击下载小狗图片</a><br/><br/> <a href="fileDownLoadServlet?name==笔记.pdf">点击下载Java笔记.pdf</a><br/><br/> <a href="fileDownLoadServlet?name=高山流水.mp3">点击下载 高山流水.mp3</a><br/><br/> </body> </html>
FileDownloadServlet
- 先准备要下载的文件[假定这些文件是公共的资源]
重要: 保证当我们的tomcat启动后,在工作目录out下有download文件夹, 并且有可供下载的文件!!
再次说明,如果你没有看到你创建的download在工作目录out下 rebuild project -> restart, 就OK - 获取到要下载的文件的名字
- 给http响应,设置响应头 Content-Type , 就是文件的MIME
通过servletContext 来获取 - 给http响应,设置响应头 Content-Disposition
这里考虑的细节比较多,比如不同的浏览器写法不一样,考虑编码
ff 是 文件名中文需要 base64, 而 ie/chrome 是 URL编码 只需知道原理
(1)如果是Firefox 则中文编码需要 base64
(2)Content-Disposition 是指定下载的数据的展示形式 , 如果attachment 则使用文件下载方式
(3)如果是其他(主流ie/chrome) 中文编码使用URL编码
- 读取下载的文件数据,返回给客户端/浏览器
(1) 创建一个和要下载的文件,关联的输入流
(2) 得到返回数据的输出流
(3) 使用工具类,将输入流关联的文件,对拷到输出流,并返回给客户端/浏览器
import org.apache.commons.io.IOUtils; import sun.misc.BASE64Encoder; import javax.servlet.ServletContext; 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.IOException; import java.io.InputStream; import java.net.URLEncoder; public class FileDownloadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("FileDownloadServlet 被调用..."); //1. 先准备要下载的文件[假定这些文件是公共的资源] // 重要: 保证当我们的tomcat启动后,在工作目录out下有download文件夹, 并且有可供下载的文件!! // 再次说明,如果你没有看到你创建的download在工作目录out下 rebuild project -> restart, 就OK //2. 获取到要下载的文件的名字 request.setCharacterEncoding("utf-8"); String downLoadFileName = request.getParameter("name"); //System.out.println("downLoadFileName= " + downLoadFileName); //3. 给http响应,设置响应头 Content-Type , 就是文件的MIME // 通过servletContext 来获取 ServletContext servletContext = request.getServletContext(); String downLoadPath = "/download/"; //下载目录从 web工程根目录计算 /download/1.jpg String downLoadFileFullPath = downLoadPath + downLoadFileName; String mimeType = servletContext.getMimeType(downLoadFileFullPath); System.out.println("mimeType= " + mimeType); response.setContentType(mimeType); //4. 给http响应,设置响应头 Content-Disposition // 这里考虑的细节比较多,比如不同的浏览器写法不一样,考虑编码 // ff 是 文件名中文需要 base64, 而 ie/chrome 是 URL编码 // 只需知道原理 // 解读 //(1)如果是Firefox 则中文编码需要 base64 //(2)Content-Disposition 是指定下载的数据的展示形式 , 如果attachment 则使用文件下载方式 //(3)如果是其他(主流ie/chrome) 中文编码使用URL编码 if (request.getHeader("User-Agent").contains("Firefox")) { // 火狐 Base64编码 response.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" + new BASE64Encoder().encode(downLoadFileName.getBytes("UTF-8")) + "?="); } else { // 其他(主流ie/chrome)使用URL编码操作 response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downLoadFileName, "UTF-8")); } //5. 读取下载的文件数据,返回给客户端/浏览器 //(1) 创建一个和要下载的文件,关联的输入流 InputStream resourceAsStream = servletContext.getResourceAsStream(downLoadFileFullPath); //(2) 得到返回数据的输出流 [因为返回文件大多数是二进制(字节), IO java基础] ServletOutputStream outputStream = response.getOutputStream(); //(3) 使用工具类,将输入流关联的文件,对拷到输出流,并返回给客户端/浏览器 IOUtils.copy(resourceAsStream, outputStream); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
总结
- 文件下载,比较麻烦的就是文件名中文处理
- 因此,在代码中,针对不同浏览器做了处理
- 对于网站的文件,很多文件使用另存为即可下载,对于大文件(文档,视频),会使用专业的下载工具(迅雷、百度,腾讯,华为网盘等)
- 对于不同的浏览器, 在把文件下载完毕后,处理的方式不一样, 有些是直接打开文件,有些是将文件下载到 本地/下载目