SpringBoot + 原生Ajax的文件流下载:blob和responseType='arrayBuffer'的关系

1. SpringBoot服务

返回文件流

@ResponseBody
@RequestMapping(value = "/exportKucunList", method = RequestMethod.POST)
public byte[] exportExcel() {
	try {
		FileInputStream fs  = new FileInputStream("d:\\TempLate.xlsx");
		byte[] bytes = new byte[fs.available()];
		fs.read(bytes);
		fs.close();
		fs = null;
		return bytes;

这里就不详细说明什么了,返回文件流byte[]就可以。
前端请求收到的内容

SpringBoot + 原生Ajax的文件流下载:blob和responseType='arrayBuffer'的关系_第1张图片

byte[]封装到JSON

如果像下面这样,想把byte[]封装到JSON(Response)对象中

@ResponseBody
@RequestMapping(value="/exportExcel", method = {RequestMethod.POST})
public Response exportExcel() {

 前端请求收到的内容是这样,然后下载的文件是无法打开的。

SpringBoot + 原生Ajax的文件流下载:blob和responseType='arrayBuffer'的关系_第2张图片

SpringBoot + 原生Ajax的文件流下载:blob和responseType='arrayBuffer'的关系_第3张图片

原因:JSON只能传递基本的数型(int,long,string等),不能传递byte类型。如果想要返回文件流,是没办法直接传输,

网上说需要用Base64 把byte[] 转成字符串,试了结果还是一样的
下面是JDK11的Base64的用法

import java.util.Base64.Encoder
import java.util.Base64.Decoder

byte[] content = new byte[fs.available()];
fs.read(content);

Encoder encoder = Base64.getEncoder();
String result = encoder.encodeToString(content );
 
Decoder decoder = Base64.getDecoder();
byte[] result = decoder.decode(str);

这个方法应该是可以的,不过懒得尝试了。

2. 原生Ajax下载文件

折腾了我一天。
Ajax.js,是我自己写的一个文件。
postDownloadFile("/service/exportExcel",param,saveFile);

原生Ajax(重点):postDownloadFile的内容

postDownloadFile: function(url, data ,callback) {
	var param = null;
	if (data) {
		param = JSON.stringify(data);
	}
	var request = new XMLHttpRequest();
		
	request.open('POST', rootPath  + url + "?timeStamp=" + new Date().getTime(), true);
	request.responseType = 'arraybuffer'
	request.setRequestHeader('Cache-Control', 'no-cache');
	request.setRequestHeader("Content-type", "application/json");
	request.onreadystatechange = function(res) {
		if (request.readyState == 4) {
			if (request.status == 200) {
				if(typeof callback === "function") {
		   		  callback(request.response)
				} 
			}
		}
	}
	request.send(param);
}

1. 在上面的代码中request.responseType = 'arraybuffer'很重要是必须的,如果不用此语句,下载的文件大小与原文件的大小不一致,而且无法打开。
responseType除了arraybuffer还有其他。
2. 使用request.responseType = 'arraybuffer'时,request.open的第三个参数必须是true
request.open('POST', rootPath  + url + "?timeStamp=" + new Date().getTime(), true);

接到后台返回的文件流,转换成Blob对象

 Blob是Web API 接口,详细的Blob信息和更多的Web Api要自己查了。

function saveFile(fileData) {
	const blob = new Blob([fileData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
	downFile(blob,"aaaa.xlsx");
}

下载到本地(网上很多,都是这么写) 

function downFile(blob, fileName) {
    if (window.navigator.msSaveOrOpenBlob) {
        navigator.msSaveBlob(blob, fileName);
    } else {
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = fileName;
        link.click();
        window.URL.revokeObjectURL(link.href);
    }
}

下载结果

源文件和下载文件大小一致

你可能感兴趣的:(SpringBoot + 原生Ajax的文件流下载:blob和responseType='arrayBuffer'的关系)