找回密码
 立即注册
首页 业界区 业界 SpringMVC流式传输媒体数据

SpringMVC流式传输媒体数据

材部 6 小时前
借助Spring的ResourceHttpRequestHandler可以实现媒体数据的传输,比如在线播放视频、预览图片等。
目前已知Spring Boot传输视频流的方法


  • 读取整个视频文件,然后把文件流写入HttpServletResponse的OutputStream。
    (此方法可行,但是需要消耗较多的服务器资源,且客户端需要下载整个视频才能播放)
  • 使用HTTP的Range实现分片加载,但是需要手动实现,比较麻烦。
  • 使用Spring自带的ResourceHttpRequestHandler是最佳实践。
思路

ResourceHttpRequestHandler是Spring Boot用于加载静态资源的一个类,默认用于从"classpath:/static"等目录读取静态资源,以便前端访问。我们可以继承它自定义一个实现。
使用方法

在项目的config包(推荐)继承ResourceHttpRequestHandler并重写getResource方法,使其返回所需要呈现给前端的资源(org.springframework.core.io.Resource)
  1. package com.example.server.config;
  2. import jakarta.servlet.http.HttpServletRequest;
  3. import org.springframework.core.io.Resource;
  4. import org.springframework.core.io.UrlResource;
  5. import org.springframework.lang.NonNull;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
  8. import java.net.MalformedURLException;
  9. import java.nio.file.Path;
  10. import java.util.List;
  11. @Component
  12. public class CustomResourceHttpRequestHandler extends ResourceHttpRequestHandler {
  13.     private Resource resource;
  14.     @Override
  15.     protected Resource getResource(@NonNull HttpServletRequest request) {
  16.         return this.resource;
  17.     }
  18.     public void setResource(Path filePath) throws MalformedURLException {
  19.         this.resource = new UrlResource(filePath.toUri());
  20.         setLocations(List.of(this.resource));
  21.     }
  22. }
复制代码
控制层注入CustomResourceHttpRequestHandler,并向setResource方法传入文件路径(java.nio.file.Path),设置请求头,最后让customResourceHttpRequestHandler处理请求。
  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.http.HttpHeaders;
  3. import org.springframework.http.HttpStatus;
  4. import org.springframework.http.ResponseEntity;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.PathVariable;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.nio.file.Path;
  12. import java.nio.file.Paths;
  13. @Controller
  14. @RequestMapping("/files")
  15. public class FileController {
  16.     @Autowired
  17.     private CustomResourceHttpRequestHandler resourceHttpRequestHandler;
  18.     @GetMapping("/{filename}")
  19.     public ResponseEntity<?> getFile(@PathVariable String filename, HttpServletRequest request, HttpServletResponse response) {
  20.         try {
  21.             // 解析文件路径
  22.             Path filePath = Paths.get("D:/StorageService").resolve(filename).normalize();
  23.             // 检查文件是否存在
  24.             if (!filePath.toFile().exists()) {
  25.                 return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  26.             }
  27.             // 设置资源路径
  28.             resourceHttpRequestHandler.setResource(filePath);
  29.             // 设置响应头,inline 会在浏览器中显示或播放文件
  30.             response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline; filename="" + filename + """);
  31.             // 让 CustomResourceHttpRequestHandler 处理请求
  32.             resourceHttpRequestHandler.handleRequest(request, response);
  33.             return new ResponseEntity<>(HttpStatus.OK);
  34.         } catch (Exception e) {
  35.             return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
  36.         }
  37.     }
  38. }
复制代码
注意点

控制层返回值需要ResponseEntity类型(org.springframework.http.ResponseEntity),且try-catch不能省略,否则可能会不断抛出异常(AsyncRequestNotUsableException和IOException)但不影响正常使用。
其他方案

如果有条件也可以使用MinIO,或者视频云点播VOD。他们提供了现成的解决方案,通过调用API可以获取视频等文件的直链。
参考资料

springboot+vue播放视频流(无需下载视频,可以拖动进度、倍速播放)

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册