需求:现在我本地电脑中有一个文件夹,文件夹中都是视频,需要实现视频播放的功能。
问题:如果通过类似 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 方法@Overrideprotected 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 {@Autowiredprivate 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