当前位置: 首页 > news >正文

java大视频在线预览(支持断点下载)

1.说明

        大视频的在线预览,如果不支持断点下载,将无法在苹果手机上播放,同时不支持进度条拖动.

        之所以这样,是因为视频文件太大了,通过二进制流向浏览器传输时,整个文件尚未传输完成时,会被浏览器强制关闭流,不再接收,等缓存播放到一定程度时,浏览器会再次向后端请求视频文件,同时附带range参数,指定获取数据范围,后端需支持对range参数的处理.

2.代码

    @ResponseBody@GetMapping(value = "/preview")@Operation(summary = "在线预览", description = "文件在浏览器中预览")public void Preview(@RequestParam String fileInfoId, HttpServletRequest request, HttpServletResponse response) throws Exception {//获取存储文件var fileInfo = fileInfoService.Get(fileInfoId);if (fileInfo == null) {response.sendError(HttpServletResponse.SC_NOT_FOUND, "File not found!");return;}//设置页面缓存if (MisFileType.PICTURE.equals(fileInfo.getFile_type()) || MisFileType.TEXT.equals(fileInfo.getFile_type())) {response.setHeader("Cache-Control", "max-age=60");//页面缓存时间60秒}//断点下载ResumeDownload(request, response, fileInfo, "inline");}/*** 支持断点重新下载文件** @param fileInfo    文件* @param disposition 下载方式 inline:内嵌 attachment:附件*/private static void ResumeDownload(HttpServletRequest request, HttpServletResponse response,FileInfoOutput fileInfo, String disposition) throws IOException {//获取存储文件String storageFilePath = FileConfig.Path + File.separator + fileInfo.getFile_path();File storageFile = new File(storageFilePath);if (!StringUtils.hasLength(storageFilePath) || !storageFile.exists()) {//相对路径未找到文件storageFilePath = fileInfo.getFile_absolute_path();//根据绝对路径寻找文件storageFile = new File(storageFilePath);if (!StringUtils.hasLength(storageFilePath) || !storageFile.exists()) {response.sendError(HttpServletResponse.SC_NOT_FOUND, "File not found!");return;}}//推断类型String mimeType = Files.probeContentType(storageFile.toPath());if (!StringUtils.hasLength(mimeType)) {URL url = new URL("file:///" + storageFilePath);mimeType = url.openConnection().getContentType();}//下载开始位置long startByte = 0;//下载结束位置long endByte = storageFile.length() - 1;//获取下载范围String range = request.getHeader("range");if (range != null && range.contains("bytes=") && range.contains("-")) {range = range.substring(range.lastIndexOf("=") + 1).trim();String[] rangeArray = range.split("-");if (rangeArray.length == 1) {//Example: bytes=1024-if (range.endsWith("-")) {startByte = Long.parseLong(rangeArray[0]);} else { //Example: bytes=-1024endByte = Long.parseLong(rangeArray[0]);}}//Example: bytes=2048-4096else if (rangeArray.length == 2) {startByte = Long.parseLong(rangeArray[0]);endByte = Long.parseLong(rangeArray[1]);}}long contentLength = endByte - startByte + 1;//HTTP 响应头设置//断点续传,HTTP 状态码必须为 206,否则不设置,如果非断点续传设置 206 状态码,则浏览器无法下载if (range != null) {log.trace("断点下载range:{},总大小:{},{}({})", range, storageFile.length(), fileInfo.getFile_name(), fileInfo.getId());response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);}if (StringUtils.hasLength(mimeType)) {response.setContentType(mimeType);response.setHeader("Content-Type", mimeType);}response.setHeader("Content-Length", String.valueOf(contentLength));response.setHeader("Accept-Ranges", "bytes");//Content-Range: 下载开始位置-下载结束位置/文件大小response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + storageFile.length());//Content-disposition: inline; filename=xxx.xxx 表示浏览器内嵌显示该文件response.setHeader("Content-Disposition", disposition + "; filename=" + URLEncoder.encode(fileInfo.getFile_name(), StandardCharsets.UTF_8));//传输文件流BufferedOutputStream outputStream = null;RandomAccessFile randomAccessFile = null;//已传送数据大小long transmittedLength = 0;try {//以只读模式设置文件指针偏移量randomAccessFile = new RandomAccessFile(storageFile, "r");randomAccessFile.seek(startByte);outputStream = new BufferedOutputStream(response.getOutputStream());byte[] buff = new byte[4096];int len;while (transmittedLength < contentLength && (len = randomAccessFile.read(buff)) != -1) {outputStream.write(buff, 0, len);transmittedLength += len;}outputStream.flush();response.flushBuffer();log.trace("下载完毕:{}-{},下载量:{},总大小:{},{}({})", startByte, endByte, transmittedLength,storageFile.length(), fileInfo.getFile_name(), fileInfo.getId());} catch (IOException e) {if (StringUtils.hasLength(range)) {response.setHeader("Content-Range", "bytes " + startByte + "-" + startByte + transmittedLength + "/" + storageFile.length());log.trace("断点下载完毕:{}-{},下载量:{},总大小:{},{}({})", startByte, endByte, transmittedLength, storageFile.length(),fileInfo.getFile_name(), fileInfo.getId());} else {log.info("下载停止:{}-{},下载量:{},总大小:{},{}({})", startByte, endByte, transmittedLength, storageFile.length(),fileInfo.getFile_name(), fileInfo.getId());}} finally {try {if (randomAccessFile != null) {randomAccessFile.close();}} catch (IOException e) {log.error("下载异常," + fileInfo.getId(), e);}}}

http://www.lryc.cn/news/240312.html

相关文章:

  • OpenCV入门10——特征点检测与匹配
  • 教育机构拒绝“数据陷阱”,群硕将英孚新一代教学管理系统搬上桌
  • 小辰的智慧树(差分+前缀和)
  • Windows如何使用key登录Linux服务器
  • k8s无法删除pv,pvc问题
  • 基于框架的线性回归
  • 万宾科技智能井盖传感器使用方式,具有什么效果?
  • 13.什么是Spring beans?
  • 算法通关村第十二关|白银|字符串经典基础面试题
  • Spring框架学习 -- 读取和存储Bean对象
  • APM工具skywalking部署
  • MFC打开可执行文件exe
  • css实现原生form表单label必填选项红色*样式,以及js控制必填校验
  • 10_6 input输入子系统,流程解析
  • 竞赛选题 题目:垃圾邮件(短信)分类 算法实现 机器学习 深度学习 开题
  • Web前端—移动Web第三天(移动Web基础、rem、less、综合案例—极速问诊)
  • MySQL--慢查询(一)
  • 【大神支招】3步,打造一张BI报表
  • 【Linux】文件操作
  • (动手学习深度学习)第13章 实战kaggle竞赛:狗的品种识别
  • 自定义注解+AOP
  • Ribbon
  • git -1
  • 基于SSM+Vue的鲜花销售系统/网上花店系统
  • 安卓:Android Studio4.0~2023中正确的打开Android Device Monitor
  • 装备制造企业设备远程运维平台的建设-天拓四方分享
  • 群晖NAS搭建WebDav服务做文件共享,可随时随地远程访问
  • c++调用Lua(table嵌套写法)
  • 算法复杂度分析
  • 几款Java源码扫描工具(FindBugs、PMD、SonarQube、Fortify、WebInspect)