logo头像
Snippet 博客主题

SpringBoot 实现视频分段播放

需求:现在我本地电脑中有一个文件夹,文件夹中都是视频,需要实现视频播放的功能。

问题:如果通过类似 SpringBoot static 文件夹的方式来实现,客户端要下载好完整的视频之后才可以播放,并且服务端也会占用大量宽带。所以这里考虑采取视频分段的方式进行下载,客户端播放视频时,可以通过进度条调节视频进度。

实现方法:在 SpringBoot 中支持自定义资源请求处理器,通过自定义的资源处理器来实现。

依赖:主要就是 SpringBoot 的相关依赖:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

编写一个自定义资源请求处理器,需要继承 ResourceHttpRequestHandler 重写 getResource() 方法。该自定义处理器还需要加上 @Component 注解。
在案例中 getResource() 方法中,需要拿到对应的视频地址,通过 Controller 层的代码通过 request.setAttribute(“video-uri”, videoUri) 设置 video-uri 的 value,value 可以是视频的本地路径,也可以是视频的唯一标识,需要按照自己的业务来传值。

    import org.springframework.core.io.FileSystemResource;
    import org.springframework.core.io.Resource;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

    import javax.servlet.http.HttpServletRequest;

    /**
     * @author 17279
     */
    @Component
    public class VideoResourceHttpRequestHandler extends ResourceHttpRequestHandler {
      // 只需要重写 getResource 方法
      @Override
      protected Resource getResource(HttpServletRequest request) {
        // 这里的 videoUri 是在 Controller 中通过 request.setAttribute("video-uri", videoUri) 进来的值
        String videoUri = (String) request.getAttribute("video-uri"); // D:\Downloads\test.mp4
        // 可以通过 videoUri 传递的值根据我们的业务查找对应的文件
        return new FileSystemResource(videoUri);
      }
    }

编写 Controller 层代码:

这里通过 request.setAttribute(“video-uri”, videoUri) 添加 video-uri 的 value,自定义处理中通过这个 value 找到向前端返回的视频。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;

    /**
     * @author 17279
     */

    @RestController
    @RequestMapping("video")
    public class VideoController {
      @Autowired
      private ResourceHttpRequestHandler resourceHttpRequestHandler;

      /**
        * @param fileName fileName 前端传递过来的视频文件名名称
        */
      @GetMapping(value = "/{fileName}")
      public void video(@PathVariable("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // 视频文件根目录【换成实际的视频根目录】
        final String videoBasePath = "D:/Downloads/";

        // 视频根目录 + 文件名称,找到对应的文件
        String videoUri = videoBasePath + fileName;
        Path videoPath = Paths.get(videoUri);

        if (Files.exists(videoPath)) {
          // 如果找到视频,那么返回视频信息
          String contentType = Files.probeContentType(videoPath);
          if (contentType != null && !"".equals(contentType)) {
            response.setContentType(contentType);
          }
          // video-path 主要是将视频的地址传递给自定义的资源处理器处使用
          request.setAttribute("video-uri", videoUri);
          resourceHttpRequestHandler.handleRequest(request, response);
        } else {
          // 如果文件不存在,那么跳到 404 页面
          response.setStatus(HttpServletResponse.SC_NOT_FOUND);
          response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
        }
      }
    }

访问地址:http://localhost/video/test.mp4

访问效果:这里设置的视频跟目录是 D:/Downloads/,前端传递的 fileName 为 test.mp4,所以实际返回前端的文件为 D:/Downloads/test.mp4

安卓学习教程公众号

微信打赏

祝你事业顺心,富贵吉祥,赞赏鼓励