实现大视频,分段下载在线播放

 

直接上代码

/**
 *方法描述: 视频实现实现分段下载

 *@param filePath  文件路径
 *@param fileName 文件名
 *@param request
 *@param response
 *@return: void
 */
@GetMapping("/videoPlay")
public void videoPlay(String filePath, String fileName, HttpServletRequest request, HttpServletResponse response) {
    RandomAccessFile targetFile = null;
    OutputStream outputStream = null;
    try {
        outputStream = response.getOutputStream();
        response.reset();
        //获取请求头中Range的值
        String rangeString = request.getHeader(HttpHeaders.RANGE);

        //打开文件
        //File file = new File(filePath);
        //防止路径操纵 不知道有没有效
        File file = FileUtils.getFile(filePath);

        if (file.exists()) {
            //使用RandomAccessFile读取文件
            targetFile = new RandomAccessFile(file, "r");
            long fileLength = targetFile.length();
            long requestSize = (int) fileLength;
            //分段下载视频
            if (StringUtils.hasText(rangeString)) {
                //从Range中提取需要获取数据的开始和结束位置
                long requestStart = 0, requestEnd = 0;
                String[] ranges = rangeString.split("=");
                if (ranges.length > 1) {
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Integer.parseInt(rangeDatas[0]);
                    if (rangeDatas.length > 1) {
                        requestEnd = Integer.parseInt(rangeDatas[1]);
                    }
                }
                if (requestEnd != 0 && requestEnd > requestStart) {
                    requestSize = requestEnd - requestStart + 1;
                }
                //根据协议设置请求头
                response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
                response.setHeader(HttpHeaders.CONTENT_TYPE, "video/mp4");
                if (!StringUtils.hasText(rangeString)) {
                    response.setHeader(HttpHeaders.CONTENT_LENGTH, fileLength + "");
                } else {
                    long length;
                    if (requestEnd > 0) {
                        length = requestEnd - requestStart + 1;
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                        response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + requestEnd + "/" + fileLength);
                    } else {
                        length = fileLength - requestStart;
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                        response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + (fileLength - 1) + "/"
                                + fileLength);
                    }
                }
                //断点传输下载视频返回206
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                //设置targetFile,从自定义位置开始读取数据
                targetFile.seek(requestStart);
            } else {
                //如果Range为空则下载整个视频
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+fileName+".mp4");
                //设置文件长度
                response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));
            }

            //从磁盘读取数据流返回
            byte[] cache = new byte[4096];
            try {
                while (requestSize > 0) {
                    int len = targetFile.read(cache);
                    if (requestSize < cache.length) {
                        outputStream.write(cache, 0, (int) requestSize);
                    } else {
                        outputStream.write(cache, 0, len);
                        if (len < cache.length) {
                            break;
                        }
                    }
                    requestSize -= cache.length;
                }
            } catch (IOException e) {
                // tomcat原话。写操作IO异常几乎总是由于客户端主动关闭连接导致,所以直接吃掉异常打日志
                //比如使用video播放视频时经常会发送Range为0- 的范围只是为了获取视频大小,之后就中断连接了
                e.printStackTrace();
            }
        } else {
            BaseException.exception(BaseErrorCode.DATA_ERROR, "文件路劲有误");
        }
        outputStream.flush();
    } catch (Exception e) {
        //文件传输错误
        BaseException.exception(BaseErrorCode.DATA_ERROR, "文件传输错误");
        e.printStackTrace();

    }finally {
        if(outputStream != null){
            try {
                outputStream.close();
            } catch (IOException e) {
                //流释放错误
                BaseException.exception(BaseErrorCode.DATA_ERROR, "文件上传,系统错误");
                e.printStackTrace();
            }
        }
        if(targetFile != null){
            try {
                targetFile.close();
            } catch (IOException e) {
                //文件流释放错误
                BaseException.exception(BaseErrorCode.DATA_ERROR, "文件流释放错误");
                e.printStackTrace();
            }
        }
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值