文件下载实现

一、概述

下载是什么?
下载其实就是向客户端响应字节数据。
把一个文件变成字节数组,然后使用response.getOutputStream()响应给浏览器。

下载的要求:
下载的要求其实可以简要概括成六个字:“两个头一个流 ”。

  • 两个头:分别为Content-Type和Content-Disposition。
    Content-Type表示的是你传递给客户端的文件的MIME类型,例如:image/pjpeg。可以通过文件名称调用ServletContext.getMimeType()方法,得到MIME类型。
    Content-Disposition的默认值为inline,表示在浏览器窗口中打开。我们要给的值是如下这种格式:attachment;filename=xxx 。在filename=后面跟随的是显示在下载框中的文件名称。
  • 一个流:就是要下载的文件数据。我们自己new一个输入流即可。

二、文件下载的示例

我们新建一个项目,并且创建一个servlet:

public class Download1Servlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 准备两个头,一个流 
		 * 1. Content-Type 
		 * 2. Content-Disposition 
		 * 3. 流:下载的文件数据
		 */
		
		String filename = "E:/test.jpg";
		// 两个头
		// 通过文件名称获取文件MIME类型
		String contentType = this.getServletContext().getMimeType(filename);
		String contentDisposition = "attachment;filename=a.jpg";
		// 创建一个数据流
		FileInputStream input = new FileInputStream(filename);

		// 接下来设置头
		response.setHeader("Content-Type", contentType);
		response.setHeader("Content-Disposition", contentDisposition);
		// 获取绑定的客户端的流
		ServletOutputStream output = response.getOutputStream();
		// 把输入流的东西写入到输出流中
		IOUtils.copy(input, output);
		input.close();
	}
}

我们直接在浏览器中访问这个servlet,我们看一下会有什么结果:

java实现excel下载居中 java下载功能实现_java实现excel下载居中


我们可以看到,弹出了一个另存为的对话框,默认的文件名就是我们设置的a.jpg。

三、有没有什么问题?

我们接着上一个示例,我们做一些更改,把文件的默认名称也就是filename=后面的内容设置为中文,我们看一下会是什么效果。
比如我们更改为:

String contentDisposition = "attachment;filename=测试用图.jpg";

我们在浏览器看一下,会是什么效果:

我们可以看到在谷歌浏览器中,文件是没有显示正确的,只显示了jpg三个字母:

java实现excel下载居中 java下载功能实现_中文乱码问题_02


我们在edge下也是不正确的:

java实现excel下载居中 java下载功能实现_java实现excel下载居中_03


而在IE(IE 11)也是不正常的:

java实现excel下载居中 java下载功能实现_JAVAWEB_04


这是为什么呢?

原因和解决办法

Firefox浏览器(上面我们并没有使用该浏览器进行测试),使用的是Base64编码。而其他的大部分浏览器,使用的都是URL编码。所以才会出现上面的情况。

我们应该怎么办呢?
其实很简单,我们只需要对文件名字符串进行一个处理,

filename = new String(filename.getBytes("GBK"),"ISO-8859-1");

上面示例的代码,我们就做以下的修改:

java实现excel下载居中 java下载功能实现_java_05


我们再测试一下:

chrome:

java实现excel下载居中 java下载功能实现_JAVAWEB_06

工具类

我们还应该注意一点,因为浏览器的不同,使用的编码方式是不同的。我们应该先获取浏览器的版本信息,然后进行相应的转码。其实我们有一个工具类,代码很简单,如下:

package com.veeja.down.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import sun.misc.BASE64Encoder;

public class DownUtils {
	public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
		String agent = request.getHeader("User-Agent"); //获取浏览器
		if (agent.contains("Firefox")) {
			BASE64Encoder base64Encoder = new BASE64Encoder();
			filename = "=?utf-8?B?"
					+ base64Encoder.encode(filename.getBytes("utf-8"))
					+ "?=";
		} else if(agent.contains("MSIE")) {
			filename = URLEncoder.encode(filename, "utf-8");
		} else {
			filename = URLEncoder.encode(filename, "utf-8");
		}
		return filename;
	}
}

这个工具类就可以获取浏览器的版本进行相应的转换。

使用这个工具类,我们再次改写我们以前的代码:

java实现excel下载居中 java下载功能实现_JAVAWEB_07


这样,我们再次测试一下:

java实现excel下载居中 java下载功能实现_中文乱码问题_08


也是完全OK的!


END.