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);}}}
相关文章:
java大视频在线预览(支持断点下载)
1.说明 大视频的在线预览,如果不支持断点下载,将无法在苹果手机上播放,同时不支持进度条拖动. 之所以这样,是因为视频文件太大了,通过二进制流向浏览器传输时,整个文件尚未传输完成时,会被浏览器强制关闭流,不再接收,等缓存播放到一定程度时,浏览器会再次向后端请求视频文件,同…...
OpenCV入门10——特征点检测与匹配
文章目录 特征检测的基本概念Harris角点检测Shi-Tomasi角点检测SIFT关键点检测SIFT计算描述子SURF特征检测OBR特征检测暴力特征匹配FLANN特征匹配实战flann特征匹配图像查找图像拼接基础知识图像拼接实战 特征点检测与匹配是计算机视觉中非常重要的内容。不是所有图像操作都是对…...
教育机构拒绝“数据陷阱”,群硕将英孚新一代教学管理系统搬上桌
为什么小机构年年担心招生不够,英孚却令学生家长趋之若鹜? 区别就在教学管理方式。为了更好地管理分布全球的校区、学生和老师,英孚应用了一套教学管理系统,帮助学校管理学员,帮老师智慧排课,帮助家长记录…...
小辰的智慧树(差分+前缀和)
登录—专业IT笔试面试备考平台_牛客网 1.考虑总长度之和不能超过m,2考虑限制每棵树高度不能低于ci,如果用二分最短输能截到的高度,还要另外去判断,是否每棵树mid都能严格大于ci ,这样容易超时,换个角度&…...
Windows如何使用key登录Linux服务器
场景:因为需要回收root管理员权限,禁止root用户远程登录,办公环境只允许普通用户远程登录,且不允许使用密码登录。 一、生成与配置ssh-key 1.使用root管理员权限登录到目标系统。 2.创建一个新的普通用户,和设置密码用…...
k8s无法删除pv,pvc问题
问题: 在k8s里面创建了pv,pvc删除时报错:error: resource(s) were provided, but no name was specified 解决: 正确的删除顺序:1.先删除pod2.再删除pv 3.在删除pvc 删除pv,pvc命令: kubect…...
基于框架的线性回归
线性回归是机器学习中最简单和最常用的回归方法之一。它建立了自变量和因变量之间的线性关系,并通过拟合一条直线或超平面来预测和分析数据。 基于框架的线性回归是构建线性回归模型的一种常见方法,它利用现有的机器学习框架来实现线性回归模型的建立、…...
万宾科技智能井盖传感器使用方式,具有什么效果?
有问题的井盖可能导致人们在行走或驾驶时不经意地踩中或碰到,从而导致摔倒、扭伤或交通事故等安全事故。有问题的井盖可能会破坏井盖和下方污水管道之间的密封性,导致污水泄漏。这不仅会对环境造成污染,还可能对公共卫生和健康构成威胁。 将智…...
13.什么是Spring beans?
什么是Spring beans? Spring 官方文档对 bean 的解释是: In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assem…...
算法通关村第十二关|白银|字符串经典基础面试题
1.反转问题 1.1 反转字符串 原题:力扣344. 要求原地修改。 public void reverseString(char[] s) {if (s null || s.length() 0) {return;}int n s.length;for (int left 0, right n - 1; left < right; left, right--) {char temp s[left];s[left] s…...
Spring框架学习 -- 读取和存储Bean对象
目录 🚀🚀 回顾 getBean()方法的使用 根据name来获取对象 再谈getBean() (1) 配置扫描路径 (2) 添加注解 ① spring注解简介 ② 对类注解的使用 ③ 注解Bean对象的命名问题 ④ 方法加Bean注解 (3) Bean 注解的重命名 (4) 获取Bean对象 -- …...
APM工具skywalking部署
一 整体架构 整个架构,分成上、下、左、右四部分: 上部分 Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等提供的 Tracing 数据信息。而我们目前采用的是&…...
MFC打开可执行文件exe
CString exeName, propathdir;//propath _T("D:\\vs2017\\Project\\work\\mySqlselect\\release64\\mySqlselect.exe");//propathdir _T("D:\\vs2017\\Project\\work\\mySqlselect\\elease64\\");//路径太深的时候要指明文件所在路径,奇葩//p…...
css实现原生form表单label必填选项红色*样式,以及js控制必填校验
文章目录 一、css实现原生form表单label必填选项红色*样式,以及js控制必填校验?二、实现方案参考原文 一、css实现原生form表单label必填选项红色*样式,以及js控制必填校验? 二、实现方案 1.css实现原生form表单label必填选项红色…...
10_6 input输入子系统,流程解析
简单分层 应用层 内核层 --------------------------- input handler 数据处理层 driver/input/evdev.c1.和用户空间交互,实现fops2.不知道数据怎么得到的,但是可以把数据上传给用户--------------------------- input core层1.维护上面和下面的两个链表2.为上下两层提供接口--…...
竞赛选题 题目:垃圾邮件(短信)分类 算法实现 机器学习 深度学习 开题
文章目录 1 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于机器学习的垃圾邮件分类 该项目…...
Web前端—移动Web第三天(移动Web基础、rem、less、综合案例—极速问诊)
版本说明 当前版本号[20231120]。 版本修改说明20231120初版 本课程的笔记已经更新完毕,各位可以通过点击《黑马程序员2023新版前端Web开发HTML5CSS3移动web视频教程,前端web入门首选》学习笔记总目录查看所有知识点,同时也能免费下载学习…...
MySQL--慢查询(一)
1. 查看慢查询日志是否开启 show variables like slow_query%; show variables like slow_query_log; 参数说明: 1、slow_query_log:这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句。 2、long_query_time:当SQL语句执行…...
【大神支招】3步,打造一张BI报表
随着BI报表的高效直观、灵活分析的特点越来越被大家所熟知,很多BI零基础的用户可积极尝试制作BI报表,以达到灵活自助分析、高效智能分析的效果。那么BI报表零基础的小白们该怎么做BI报表,才能又快又好地做出来? 大神支招…...
【Linux】文件操作
欢迎来到Cefler的博客😁 🕌博客主页:那个传说中的man的主页 🏠个人专栏:题目解析 🌎推荐文章:题目大解析(3) 目录 👉🏻文件是什么?&am…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
