把视频文件作为流返回给客户端

news/2024/12/12 9:24:27/

1.页面浏览器请求:

2. 读取文件:

java">@GetMapping("/read")
@ApiOperation(value = "视频读取", httpMethod = "GET", response = ResponseMessage.class, notes = "tst")
public void test(HttpServletRequest request, HttpServletResponse response, @RequestParam String filePath) {if (filePath.contains("%")) {try {filePath = URLDecoder.decode(filePath, "UTF-8");} catch (UnsupportedEncodingException e) {}}if (filePath.contains("%")) {try {filePath = URLDecoder.decode(filePath, "UTF-8");} catch (UnsupportedEncodingException e) {}}ServletOutputStream out = null;FileInputStream in = null;try {String path = systemProperties.getDir() + FilenameUtils.getName(filePath);readFileAsResponse(request, response, new File(path), "");} catch (FileNotFoundException e) {} catch (Exception e) {} finally {try {out.close();in.close();} catch (NullPointerException e) {} catch (Exception e) {}}
}
java"> /*** 播放把文件作为流返回给客户端** @throws IOException*/
public static void readFileAsResponse(HttpServletRequest request, HttpServletResponse response, File readfile, String fileName2) throws IOException {InputStream is1 = null;OutputStream os2 = null;try {is1 = new FileInputStream(readfile);long fileSizeNumber = readfile.length();if (StringUtils.isBlank(fileName2)) {fileName2 = readfile.getName();}String suffix = fileName2.substring(fileName2.lastIndexOf(".") + 1);String videoSuffix = "mp4";if (videoSuffix.equalsIgnoreCase(suffix)) {response.setContentType("video/mp4");} else {response.setContentType("application/octet-stream");}response.setHeader("Accept-Ranges", "bytes");String range = request.getHeader("Range");// 返回的状态码,默认200,首次下载int status = HttpServletResponse.SC_OK;// 如果range下载区域为空,则首次下载,if (range == null) {range = "bytes=0-";} else {// 客户发送了一个带有Range头的GET请求status = HttpServletResponse.SC_PARTIAL_CONTENT;}long start = 0, end = 0;String startsWithFlag = "bytes=";if (null != range && range.startsWith(startsWithFlag)) {//处理start为负数和start end为非正整数String rangeStart = range.split("=")[1].substring(0, 1);String equalsFlag = "-";if (equalsFlag.equals(rangeStart)) {ResponseMessage responseMessage = new ResponseMessage();responseMessage.setCode(CodeMessageUtil.CodeEnum.CODE_1039.getCode().toString());responseMessage.setMessage(CodeMessageUtil.CodeEnum.CODE_1039.getDesc());responseMessage.result("失败!");ResponseUtil.setResponse(response, responseMessage.toString());return;}String[] values = range.split("=")[1].split("-");//验证start的整数性 (正则匹配)if (validate(String.valueOf(values[0]), Validation.INT) == false) {ResponseMessage responseMessage = new ResponseMessage();responseMessage.setCode(CodeMessageUtil.CodeEnum.CODE_1039.getCode().toString());responseMessage.setMessage(CodeMessageUtil.CodeEnum.CODE_1039.getDesc());responseMessage.result("失败!");ResponseUtil.setResponse(response, responseMessage.toString());return;}start = Long.parseLong(values[0]);// 如果服务器端没有设置end结尾,默认取下载全部if (values.length == 1) {end = fileSizeNumber - 1;} else {//验证end的整数性(正则匹配)if (validate(String.valueOf(values[1]), Validation.INT) == false) {ResponseMessage responseMessage = new ResponseMessage();responseMessage.setCode(CodeMessageUtil.CodeEnum.CODE_1039.getCode().toString());responseMessage.setMessage(CodeMessageUtil.CodeEnum.CODE_1039.getDesc());responseMessage.result("失败!");ResponseUtil.setResponse(response, responseMessage.toString());return;}end = Long.parseLong(values[1]);//当end设置过长是,把end设置成文件大小if (end + 1 > fileSizeNumber) {end = fileSizeNumber - 1;}}}// 此次数据响应大小long responseSize = 0;if (end != 0 && end > start) {responseSize = end - start + 1;// 返回当前连接下载的数据大小,也就是此次数据传输大小response.addHeader("Content-Length", "" + (responseSize));} else {responseSize = Integer.MAX_VALUE;}byte[] buffer = new byte[4096];// 设置响应状态码response.setStatus(status);// 设置断点续传的Content-Range传输字节和总字节response.addHeader("Content-Range", "bytes " + start + "-" + (fileSizeNumber - 1) + "/" + fileSizeNumber);// 当前需要下载文件的大小long needSize = responseSize;if (start != 0) {// 跳已经传输过的字节is1.skip(start);}os2 = response.getOutputStream();while (needSize > 0) {int len = is1.read(buffer);if (needSize < buffer.length) {os2.write(buffer, 0, (int) needSize);} else {os2.write(buffer, 0, len);// 如果读取文件大小小于缓冲字节大小,表示已写入完,直接跳出if (len < buffer.length) {break;}}// 不断更新当前可下载文件大小needSize -= buffer.length;}os2.flush();} catch (IOException e) {} finally {if (is1 != null) {is1.close();}if (os2 != null) {os2.close();}}
}


http://www.ppmy.cn/news/1554456.html

相关文章

Github2024-12-10 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-12-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10HTML项目1Rust项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次关注人…

【前端】JavaScript中的闭包与垃圾回收机制详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;垃圾回收机制&#xff08;Garbage Collection, GC&#xff09;垃圾回收的核心原理核心过程 函数作用域与垃圾回收运行分析输出结果 垃圾回收的局限性与挑战 &#x1f4a…

Python+OpenCV系列:图像的运算

文章目录 PythonOpenCV系列&#xff1a;图像的加权和、覆盖1. 图像加权和&#xff08;加权融合&#xff09;2. 图像覆盖&#xff08;区域叠加&#xff09;3. 应用场景4. 总结 PythonOpenCV系列&#xff1a;图像的加权和、覆盖 在图像处理中&#xff0c;图像的加权和与覆盖是两…

探索视觉与语言模型的可扩展性

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

golang实现简单的redis服务4.0(持久化)

redis的持久化机制与实现原理RDB工作原理问题1:如果数量很大怎么办?问题2:子线程在持久化期间有新的数据写入会发生什么?如何保证数据一致性? AOF的原理如何解决aof文件越来越大的问题aof文件如何重写?aof如何恢复数据aof文件有问题(损坏了)恢复会发生什么?怎么办?aof有哪…

OpenGL ES详解——多个纹理实现混叠显示

目录 一、获取图片纹理数据 二、着色器编写 1. 顶点着色器 2. 片元着色器 三、绑定和绘制纹理 1. 绑定纹理 2. 绘制纹理 四、源码下载 一、获取图片纹理数据 获取图片纹理数据代码如下&#xff1a; //获取图片1纹理数据 mTextureId loadTexture(mContext, R.mipmap.…

基于java+SSM+Vue的家庭记账本小程序设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

前端新手教程:HTML、CSS 和 JavaScript 全面详解及实用案例

一、引言 在当今数字化的时代&#xff0c;前端开发扮演着至关重要的角色&#xff0c;它决定了用户与网页和应用程序交互的体验。HTML、CSS 和 JavaScript 作为前端开发的核心技术&#xff0c;分别负责网页的结构、样式和交互。本教程将为前端新手全面深入地介绍 HTML、CSS 和 …