厦门地税网站建设,平台类网站有哪些,wordpress用户注册登录插件,wordpress主题背景学习链接
SpringBootvue文件上传下载预览大文件分片上传文件上传进度
Blob File FileReader ArrayBuffer
VueSpringBoot实现文件的分片下载
video标签学习 xgplayer视频播放器分段播放mp4#xff08;Range请求交互过程可以参…学习链接
SpringBootvue文件上传下载预览大文件分片上传文件上传进度
Blob File FileReader ArrayBuffer
VueSpringBoot实现文件的分片下载
video标签学习 xgplayer视频播放器分段播放mp4Range请求交互过程可以参考这个里面的截图
【java】java实现大文件的分片上传与下载springbootvue3)代码已fork至本地
代码
FileController
这里面的代码实现完全可以参考ResourceHttpRequestHandler#handleRequest
RestController
public class FileController {private static final int BUFFER_SIZE 4 * 1024;RequestMapping(path chunkdownload, method {RequestMethod.HEAD, RequestMethod.POST})public void chunkdownload(HttpServletRequest request, HttpServletResponse response) throws Exception {File file new File(D:/usr/test/demo.mp4);// 文件总大小long fileSize file.length();// 设置 Content-Type 和 相关响应头// (这里分片下载响应头设置, 其实可以参考ResourceHttpRequestHandler#handleRequest,// 和 video标签学习 xgplayer视频播放器分段播放mp4 - https://blog.csdn.net/qq_16992475/article/details/130945997)response.setContentType(application/octect-stream;charsetUTF-8);response.setHeader(Content-Disposition, attachment; filename\ file.getName() \);response.setHeader(Accept-Ranges, bytes);// 检查请求头中是否有Range请求头,// (可参考video标签学习 xgplayer视频播放器分段播放mp4 - https://blog.csdn.net/qq_16992475/article/details/130945997)String rangeHeader request.getHeader(Range);// 没有Range请求头, 则下载整个文件if (rangeHeader null) {response.setHeader(Content-Length, String.valueOf(fileSize));InputStream in new FileInputStream(file);OutputStream out response.getOutputStream();// 字节缓冲数组byte[] buffer new byte[BUFFER_SIZE];int bytesRead -1;// 读取多少, 写多少, 直到读取完毕为止while ((bytesRead in.read(buffer)) ! -1) {out.write(buffer, 0, bytesRead);}in.close();out.close();} else {// 分片下载// (可参考: 参考ResourceHttpRequestHandler#handleRequest中的做法)// 开始索引long start 0;// 结束索引long end fileSize - 1;// 获取Range请求头的范围, 格式为Range: bytes0-8055,// (其中可能没有结束位置, 若没有位置, 取文件大小-1)String[] range rangeHeader.split()[1].split(-);// 如果Range请求头中没有结束位置, 取文件大小-1if (range.length 1) {start Long.parseLong(range[0]);end fileSize - 1;} else {// 解析开始位置 和 结束位置start Long.parseLong(range[0]);end Long.parseLong(range[1]);}// 此次要写出的数据long contentLength end - start 1;// 返回头里存放每次读取的开始和结束字节response.setHeader(Content-Length, String.valueOf(contentLength));// 响应状态码206response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);// Content-Range响应头格式为Content-Range: bytes 0-8055/9000response.setHeader(Content-Range, bytes start - end / fileSize);InputStream in new FileInputStream(file);OutputStream out response.getOutputStream();// 跳到第start字节in.skip(start);// 字节缓冲数组byte[] buffer new byte[BUFFER_SIZE];// 读取的字节数量int bytesRead -1;// 写出的字节数量long bytesWritten 0;while ((bytesRead in.read(buffer)) ! -1) {// 如果 已写入的数据 当前已读到的数据 超过了 此次要写出的数据, 则只能写入请求范围内的数据if (bytesWritten bytesRead contentLength) {out.write(buffer, 0, (int) (contentLength - bytesWritten));break;} else {out.write(buffer, 0, bytesRead);bytesWritten bytesRead;}}in.close();out.close();}}}ChunkDownload.vue
先发1个head请求获取到文件的大小再发post请求获取每个分片其中为了简单理解就不引入async-await的使用了将获取的每个分片组合为单个文件
templatediv classgapel-button clickdownloadChunks分片下载demo.mp4/el-button/div
/templatescript
import axios from axiosexport default {name: ChunkDownload,components: {},methods: {downloadChunks() {const chunkdownloadUrl http://localhost:8085/chunkdownload// 分片下载大小 5MBconst chunkSize 1024 * 1024 * 5;// 文件总大小(需要请求后端获得)let fileSize 0;axios.head(chunkdownloadUrl).then(res {// 定义 存储所有的分片的数组let chunks [];// 获取文件总大小fileSize res.headers[content-length]// 计算分片数量const chunksNum Math.ceil(fileSize / chunkSize)// 定义下载文件分片的方法function downloadChunkFile(chunkIdx) {if (chunkIdx chunksNum) {alert(分片索引不可超过分片数量)return}let start chunkIdx * chunkSizelet end Math.min(start chunkSize - 1, fileSize - 1)const range bytes${start}-${end};axios({url: chunkdownloadUrl,method: post,headers: {Range: range},responseType: arraybuffer}).then(response {chunks.push(response.data)if(chunkIdx chunksNum - 1) {// 下载好了console.log(chunks, chunks);// 组合chunks到单个文件const blob new Blob(chunks);console.log(blob, blob);const link document.createElement(a);link.href window.URL.createObjectURL(blob);link.download demo.mp4;link.click();return} else {chunkIdxdownloadChunkFile(chunkIdx)}})}downloadChunkFile(0)})}}
}
/scriptstyle
.gap {padding: 10px;
}
/style测试