视频续播功能实现 – 断点续看从前端到 Spring Boot 后端

随着在线视频平台的普及,用户常常遇到中途停止观看的情况,例如网络不稳定、用户主动暂停等。在这种情况下,如何确保用户能够从上次观看的进度继续观看,而不是从头开始,成为了在线视频服务中非常重要的一项功能。本文将介绍如何实现 视频续播功能,从前端到后端的完整实现过程。

一、视频续播功能概述

视频续播功能,也称为 断点续看,其核心思想是记录用户观看视频的进度,并将这个进度保存下来,在用户重新观看时能够继续从上次停止的地方开始播放。

具体的功能实现包括:

  1. 前端页面通过 HTML5 Video 标签获取并记录视频的播放进度。
  2. 前端通过 AJAX 向后端发送用户的观看进度。
  3. 后端使用 Spring Boot 接收并保存用户的观看进度。
  4. 后端在用户重新访问时,返回用户上次观看的进度信息。

二、技术栈

  • 前端:HTML5、JavaScript、AJAX
  • 后端:Spring Boot、Spring Data JPA、MySQL
  • 数据库:MySQL
  • 服务器:Tomcat

三、系统设计

3.1 数据库设计

为了保存用户观看的视频进度,需要在数据库中设计一张表来存储每个用户的视频观看进度。数据库表设计如下:

CREATE TABLE video_progress (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    video_id INT NOT NULL,
    progress DECIMAL(5, 2) NOT NULL,  -- 记录观看进度(单位:秒)
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (video_id) REFERENCES videos(id)
);
  • user_id:用户的ID。
  • video_id:视频的ID。
  • progress:用户观看到的视频进度,以秒为单位。
  • last_updated:记录更新时间。

3.2 后端设计

后端使用 Spring Boot 框架来处理视频播放进度的保存与获取。

3.2.1 保存视频进度

当用户观看视频时,前端定期将观看进度通过 AJAX 发送到后端,后端会将进度保存到数据库中。

@RestController
@RequestMapping("/api/video")
public class VideoController {

    @Autowired
    private VideoProgressService videoProgressService;

    // 保存观看进度
    @PostMapping("/progress")
    public ResponseEntity<String> saveProgress(@RequestBody VideoProgressDTO progressDTO) {
        videoProgressService.saveProgress(progressDTO);
        return ResponseEntity.ok("Progress saved successfully.");
    }

    // 获取视频进度
    @GetMapping("/progress/{userId}/{videoId}")
    public ResponseEntity<Double> getProgress(@PathVariable int userId, @PathVariable int videoId) {
        double progress = videoProgressService.getProgress(userId, videoId);
        return ResponseEntity.ok(progress);
    }
}

VideoProgressDTO

public class VideoProgressDTO {
    private int userId;
    private int videoId;
    private double progress;  // 观看进度(单位:秒)

    // Getter and Setter
}
3.2.2 VideoProgressService

该服务用于处理视频观看进度的保存和获取。

@Service
public class VideoProgressService {

    @Autowired
    private VideoProgressRepository videoProgressRepository;

    // 保存进度
    public void saveProgress(VideoProgressDTO progressDTO) {
        VideoProgress videoProgress = videoProgressRepository.findByUserIdAndVideoId(progressDTO.getUserId(), progressDTO.getVideoId());
        if (videoProgress == null) {
            videoProgress = new VideoProgress();
            videoProgress.setUserId(progressDTO.getUserId());
            videoProgress.setVideoId(progressDTO.getVideoId());
        }
        videoProgress.setProgress(progressDTO.getProgress());
        videoProgressRepository.save(videoProgress);
    }

    // 获取进度
    public double getProgress(int userId, int videoId) {
        VideoProgress videoProgress = videoProgressRepository.findByUserIdAndVideoId(userId, videoId);
        return videoProgress != null ? videoProgress.getProgress() : 0.0;
    }
}
3.2.3 VideoProgressRepository

使用 JPA 来处理数据库操作。

@Repository
public interface VideoProgressRepository extends JpaRepository<VideoProgress, Integer> {

    VideoProgress findByUserIdAndVideoId(int userId, int videoId);
}

3.3 前端设计

前端通过 HTML5 Video 标签显示视频,使用 JavaScript 来记录视频的播放进度,并通过 AJAX 定期将进度发送到后端。

3.3.1 HTML5 Video 标签
<video id="videoPlayer" width="600" controls>
    <source src="video.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
3.3.2 JavaScript 监听播放进度
let video = document.getElementById("videoPlayer");
let userId = 1;  // 假设当前用户ID为1
let videoId = 123;  // 假设当前视频ID为123

// 定期发送播放进度到后端
setInterval(function() {
    let progress = video.currentTime;  // 获取视频播放进度(单位:秒)
    saveProgress(userId, videoId, progress);
}, 5000);  // 每5秒钟发送一次进度

// 保存进度到后端
function saveProgress(userId, videoId, progress) {
    fetch('/api/video/progress', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ userId: userId, videoId: videoId, progress: progress })
    })
    .then(response => response.json())
    .then(data => console.log('Progress saved:', data))
    .catch(error => console.error('Error:', error));
}

// 获取用户上次观看的进度
function getProgress(userId, videoId) {
    fetch(`/api/video/progress/${userId}/${videoId}`)
        .then(response => response.json())
        .then(data => {
            // 设置视频播放进度
            if (data > 0) {
                video.currentTime = data;
                video.play();
            }
        })
        .catch(error => console.error('Error:', error));
}
3.3.3 页面加载时获取进度

当用户再次访问视频页面时,前端需要从后端获取上次观看的进度,并将视频跳转到对应的位置。

window.onload = function() {
    getProgress(userId, videoId);
};

四、测试与调试

4.1 测试用例

  1. 保存进度
    • 用户观看视频并在中途暂停或离开。
    • 前端定期将视频进度通过 AJAX 发送到后端。
    • 后端接收到请求后将进度保存到数据库中。
  2. 获取进度
    • 用户重新访问视频页面。
    • 前端通过 AJAX 请求获取用户上次观看的进度。
    • 后端返回存储在数据库中的进度,前端将视频跳转到上次观看的进度,并继续播放。

4.2 调试建议

  • 使用浏览器开发者工具查看 AJAX 请求和响应,确保进度数据正确传输。
  • 使用 Postman 或 cURL 测试后端接口的正确性。

五、总结

本文介绍了如何实现一个完整的视频续播(断点续看)功能,涵盖了从 前端 到 后端 的实现过程。在前端,我们利用 HTML5 Video 标签和 JavaScript 实现了视频播放进度的记录与获取;在后端,我们通过 Spring Boot和 JPA 存储用户观看进度并提供 API 接口供前端调用。通过这种方式,用户可以在不同时间段断开观看后,通过续播功能继续观看视频,而无需从头开始。