后端如何将文件传给前端??
一般后端通过流输出文件,前端直接get请求下载,但是这样功能受限了,这个请求的响应中很难附带其他信息,虽然其他信息可以放在请求头中,但是这样很不优雅。很多时候一个请求的响应中应该即包含文件,也包含其他信息,例如:
后端向前端传文件的方式有很多种:
1、对于js可以创建的文件,如excel pdf等,可以将文件数据通过json传给前端,由前端生成文件
2、后端创建文件 ,读取文件的二进制数组,通过List传给前端(在spring mvc中 byte[] 会自动转成base64字符串)
3、后端创建文件,读取文件的二进制数组,转成base64字符串传给前端
4、后端将文件串给云存储(七牛云),然后返给前端下载链接。
ps: 很多数格式的文件都不需要在后端生成物理文件,拿到二进制数据即可:
public static byte[] getByte(String sheetName, Class clazz, List data){
ByteArrayOutputStream bout = new ByteArrayOutputStream();
EasyExcel.write(bout, clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).doWrite(data);
return bout.toByteArray();
}
方法 1 js生成excel pdf 的工具包通常比较大,其实不太友好
方法 1,2,3 文件不持久化,文件与数据一起返回给前端,占用应用服务器带宽资源,只适合访问压力小的 B端 、A端(管理端)应用
方法 4 文件会持久化(可能需要定期删除),但是不占用应用服务器资源(云存储服务的带宽和流量非常便宜),适合压力较大的 C端应用
这里介绍 方法 2,3 的实现方式:
public class Result {
List<Byte> data ;
String base64Str;
}
前端 读取base64生成文件:
const util = {
/** 通过base64字符串生成文件 */
downloadFileByBase64: function(base64Str, fileName) {
var myBlob = this.dataURLtoBlob(base64Str)
var myUrl = URL.createObjectURL(myBlob)
this.downloadFile(myUrl, fileName)
},
/**封装base64Str blob对象*/
dataURLtoBlob: function (base64Str) {
var bstr = atob(base64Str), n = bstr.length, u8arr = new Uint8Array(n);
alert(JSON.stringify(bstr))
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr]);
},
/**创建一个a标签,并做下载点击事件*/
downloadFile: function (hrefUrl, fileName) {
var a = document.createElement("a")
a.setAttribute("href", hrefUrl)
a.setAttribute("download", fileName)
a.setAttribute("target", "_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
}
}
export default util
LoadFileUtil.downloadFileByBase64(response.data.base64Str,“test.xlsx”)
核心代码:
这里最重要的代码
window.atob(base64Str) -------- 解码base64 不过解码后依然是字符串
u8arr = new Uint8Array(n); u8arr[n] = bstr.charCodeAt(n); ------- 返回字符串编码 且用位长为 8 的数组保存(后端一个byte长度也是8)
前端 读取二进制数组生成文件:
const util = {
/**创建一个a标签,并做下载点击事件*/
downloadFile: function (hrefUrl, fileName) {
var a = document.createElement("a")
a.setAttribute("href", hrefUrl)
a.setAttribute("download", fileName)
a.setAttribute("target", "_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
},
buildBlobByByte:function(data){
let len = data.length;
let u8arr = new Uint8Array(len);
while(len -- ){
u8arr[len] = data[len];
}
return new Blob([u8arr]);
},
/**二进制数组 生成文件 */
downloadFileByByte:function(data, fileName) {
var myBlob = this.buildBlobByByte(data)
var myUrl = URL.createObjectURL(myBlob)
this.downloadFile(myUrl, fileName)
}
}
export default util
LoadFileUtil.downloadFileByByte(response.data.data,“test-byte.xlsx”)
核心代码:
let u8arr = new Uint8Array(len);
while(len – ){
u8arr[len] = data[len];
}
后端的byte数组传递的时候通过json传递,实际上js可能用整数接收的,所有在内存中占有的空间大(后端一个byte是8位,前端可能用16位接收),得到的二进制数组实际上是不对的,所有通过赋值给Uint8Array将它们转成正常的