java实现大文件下载,前端js配合

/ 0条评论 / 0 个点赞 / 560人阅读

后端代码

public void exportData(HttpServletRequest request, HttpServletResponse response) {
		// 临时文件
		File tempFile = null;
		try {
			String datetime = DateUtils.formatDateYYYYMMDDHHMMSS(new Date());
			response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8") + datetime + ".xls");
			response.setHeader("Content-Length", String.valueOf(new File(path).length()));
			response.setContentType("application/vnd.ms-excel;charset=utf-8");
			
			//大文件下载
			try (RandomAccessFile randomAccessFile = new RandomAccessFile(new File(path), "r");
	             OutputStream outputStream = response.getOutputStream()) {
	            byte[] buffer = new byte[1024];
	            int bytesRead;
	            while ((bytesRead = randomAccessFile.read(buffer)) != -1) {
	                outputStream.write(buffer, 0, bytesRead);
	                outputStream.flush();
	            }
	        }
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}

	}

js代码

创建dowload.js文件,内容如下:

// status
const DONE = 4;

// range size
const RANGE_SIZE = 100;

// get content length
function getContentLength(url) {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open('HEAD', url, true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == DONE) {
                resolve(this.getResponseHeader('Content-Length'));
            }
        }
        xhr.send();
    })
}

// get range content
function getRangeContent(startIndex, endIndex, dowObj) {
	
	var html='<div class="layui-progress" lay-showpercent="true"  style="width: 100%;top: 0px;position: absolute;" lay-showpercent="true" lay-filter="D_">';
	html+='<div class="layui-progress-bar layui-bg-blue" lay-percent="0%" ></div>';
	html+='</div>';
	if($("#breadcrumbs").length>0){
		$("#breadcrumbs").append(html);
	}else{
		$("body").append(html);
	}
	//如果初始进度大于0,则每秒加载一个进度
	var interalTempProgress,tempProgress=0;
	if((dowObj.initProgress||0)>0){
		interalTempProgress = setInterval(setTempProgress,(dowObj.initTime||1000));
    	function setTempProgress(){
    		tempProgress++;
			$("[lay-filter='D_']").find('.layui-progress-bar').width(tempProgress+"%");
    	}
	}
	
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', dowObj.url, true);
        xhr.setRequestHeader('Range', `bytes=${startIndex}-${endIndex}`);
        xhr.responseType = 'arraybuffer';
        xhr.onreadystatechange = function () {
            if (xhr.readyState == DONE) {
                console.log(xhr.response)
                //文件名称
				var filename = xhr.getResponseHeader('Content-Disposition').split(';')[1].split('=')[1];
				filename = decodeURIComponent(filename.replace(/\+/g,'%20'));//解码之前先解决加号问题
				var backObj = {};
				backObj.fileName=filename;
				backObj.response=xhr.response;
                resolve(backObj);
            }
        }
        xhr.addEventListener('progress',function(event){
			// 计算出百分比
			var percent  = ((event.loaded / event.total) * 100).toFixed(2);
			console.log("导出进度:"+percent);
			if(percent>(dowObj.initProgress||0)){
				if((dowObj.initProgress||0)>0){
					//清除计时器
					clearInterval(interalTempProgress);
				}
				$("[lay-filter='D_']").find('.layui-progress-bar').width(percent+"%");
			}
			if(percent>=100){
				$("[lay-filter='D_']").remove();
				layer.msg("下载完成!");
			}
		}, false);
        xhr.send();
    })
}

// download arraybuffer file
function downloadArrayBufferFile(arrayBuffer, fileName) {
    const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = fileName;
    a.click();
}

// concat arraybuffer array
function concatArrayBuffer(arrayBufferArray) {
    let totalLength = 0;
    arrayBufferArray.forEach(arrayBuffer => {
        totalLength += arrayBuffer.byteLength;
    });
    const result = new Uint8Array(totalLength);
    let offset = 0;
    arrayBufferArray.forEach(arrayBuffer => {
        result.set(new Uint8Array(arrayBuffer), offset);
        offset += arrayBuffer.byteLength;
    });
    return result;
}

// main methoeds
async function myDowloadFile(dowObj) {
    /*const contentLength = await getContentLength(fileUrl);
    const numberRequest = Math.ceil(contentLength / RANGE_SIZE);
    const arrayBufferArray = [];
    for (let i = 0; i < numberRequest; i++) {
        const startIndex = i * RANGE_SIZE;
        const endIndex = startIndex + RANGE_SIZE - 1;
        const clip = await getRangeContent(startIndex, endIndex, fileUrl);
        arrayBufferArray.push(clip);
    }*/
    
    const arrayBufferArray = [];
    const startIndex = 0;
    const endIndex = 99;
    const backObj = await getRangeContent(startIndex, endIndex, dowObj);
    arrayBufferArray.push(backObj.response);
    const result = concatArrayBuffer(arrayBufferArray);
    downloadArrayBufferFile(result,backObj.fileName);
}

调用方式

myDowloadFile({
	url:'exportController.do?commonExportList&serverName=tBBdataBasicService&fileName=不可移动文物查询导出&'+temp,//下载地址
	initProgress:20,//初始进度
	initTime:1000//初始进度范围内多少秒加载一个百分比,默认为1秒
	});