背景:前端一般展示页面播放视频都是从头加载视频,这样会使用户体现很差,网速不好快进的话就会卡顿,加载太慢,为了 解决这一问题,后台给前端提供的接口需要实现断点下载的功能
- @ApiOperation(value = "视频播放一方法", notes = "视频播放一方法")
- @GetMapping(value = "/preview")
- @ApiImplicitParams({
- @ApiImplicitParam(name = "url", value = "文件路径", required = true,paramType = "query")
- })
- @Override
- public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
- // TODO Auto-generated method stub
- HttpServletRequest request=(HttpServletRequest)req;
- HttpServletResponse response=(HttpServletResponse)res;
- System.out.println(req.getParameter("url"));
- String path = addMinioUrl.getObPath(req.getParameter("url"));
- //String path="E:/video/111.mp4";
- RandomAccessFile targetFile = null;
- OutputStream outputStream = null;
- try {
- outputStream = response.getOutputStream();
- response.reset();
- //获取请求头中Range的值
- String rangeString = request.getHeader(HttpHeaders.RANGE);
-
- //打开文件
- File file = new File(path);
- 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=test.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- 的范围只是为了获取视频大小,之后就中断连接了
- //log.info(e.getMessage());
- //throw new RuntimeException(e);
- }
- } else {
- // throw new RuntimeException("文件路劲有误");
- }
- outputStream.flush();
- } catch (Exception e) {
- // e.printStackTrace();
- // throw new RuntimeException("文件传输错误");
- }finally {
- if(outputStream != null){
- try {
- outputStream.close();
- } catch (IOException e) {
- //e.printStackTrace();
- // throw new RuntimeException("流释放错误");
-
- }
- }
- if(targetFile != null){
- try {
- targetFile.close();
- } catch (IOException e) {
- //e.printStackTrace();
- // throw new RuntimeException("文件流释放错误");
- }
- }
- }
-
- }
前端要安装视频插件,需要的小伙伴可以@我