从数据库到播放器:Java视频续播功能完整实现解析

在Java中实现视频续播功能,通常需要结合后端存储(如数据库)和前端播放器配合。以下是关键步骤和代码示例:


实现思路

  1. 记录播放进度:播放时定期保存当前播放位置

  2. 存储进度数据:将进度关联用户/设备ID和视频ID存储

  3. 恢复播放:再次打开视频时读取上次保存的位置

  4. 前端配合:播放器跳转到指定时间点


后端实现(Spring Boot示例)

1. 实体类 - 播放记录
java 复制代码
@Entity
public class VideoProgress {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String userId;    // 用户标识(可用设备ID替代)
    private String videoId;   // 视频唯一标识
    private double lastPosition; // 最后播放位置(秒)
    private Date updateTime;
    
    // getters/setters
}
2. Repository接口
java 复制代码
public interface VideoProgressRepository extends JpaRepository<VideoProgress, Long> {
    VideoProgress findByUserIdAndVideoId(String userId, String videoId);
}
3. Service层
java 复制代码
@Service
public class VideoService {
    
    @Autowired
    private VideoProgressRepository progressRepo;

    // 保存播放进度
    public void savePlaybackPosition(String userId, String videoId, double position) {
        VideoProgress progress = progressRepo.findByUserIdAndVideoId(userId, videoId);
        
        if (progress == null) {
            progress = new VideoProgress();
            progress.setUserId(userId);
            progress.setVideoId(videoId);
        }
        
        progress.setLastPosition(position);
        progress.setUpdateTime(new Date());
        progressRepo.save(progress);
    }

    // 获取播放进度
    public double getLastPosition(String userId, String videoId) {
        VideoProgress progress = progressRepo.findByUserIdAndVideoId(userId, videoId);
        return (progress != null) ? progress.getLastPosition() : 0;
    }
}
4. Controller层
java 复制代码
@RestController
@RequestMapping("/api/video")
public class VideoController {
    
    @Autowired
    private VideoService videoService;

    // 更新进度接口
    @PostMapping("/progress")
    public ResponseEntity<Void> updateProgress(
            @RequestParam String userId,
            @RequestParam String videoId,
            @RequestParam double position) {
        
        videoService.savePlaybackPosition(userId, videoId, position);
        return ResponseEntity.ok().build();
    }

    // 获取进度接口
    @GetMapping("/progress")
    public ResponseEntity<Double> getProgress(
            @RequestParam String userId,
            @RequestParam String videoId) {
        
        double position = videoService.getLastPosition(userId, videoId);
        return ResponseEntity.ok(position);
    }
}

前端实现(JavaScript示例)

使用HTML5 video标签配合AJAX请求:

html 复制代码
<video id="myPlayer" controls>
  <source src="/videos/sample.mp4" type="video/mp4">
</video>

<script>
const player = document.getElementById('myPlayer');
const userId = "device123"; // 实际中从登录信息获取
const videoId = "video456";

// 1. 尝试获取历史进度
fetch(`/api/video/progress?userId=${userId}&videoId=${videoId}`)
  .then(res => res.json())
  .then(position => {
    if(position > 0) {
      player.currentTime = position; // 跳转到续播位置
    }
  });

// 2. 定时保存播放进度(每5秒)
setInterval(() => {
  if(!player.paused) {
    const position = player.currentTime;
    fetch(`/api/video/progress?userId=${userId}&videoId=${videoId}&position=${position}`, {
      method: 'POST'
    });
  }
}, 5000); // 5秒保存一次

// 3. 视频结束时重置进度(可选)
player.addEventListener('ended', () => {
  fetch(`/api/video/progress?userId=${userId}&videoId=${videoId}&position=0`, {
    method: 'POST'
  });
});
</script>

关键优化点

  1. 节流控制 :使用setTimeout替代setInterval避免并发问题

  2. 本地缓存:可先用localStorage暂存进度,网络恢复后同步到服务器

  3. 进度验证:后端校验position不超过视频总时长

  4. 过期策略:超过30天的进度自动清除

  5. 并发处理:使用@Transactional保证数据一致性


数据库表结构(MySQL示例)

sql 复制代码
CREATE TABLE video_progress (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(64) NOT NULL,
  video_id VARCHAR(64) NOT NULL,
  last_position DOUBLE NOT NULL DEFAULT 0,
  update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY (user_id, video_id)
);

扩展场景

  1. 多端同步:用户在不同设备续播

  2. 断点续传:结合视频分片技术(HLS/DASH)

  3. 历史记录:展示所有观看过的视频进度

  4. 智能续播:超过95%进度视为已完成

提示:实际生产环境中建议使用Redis缓存播放进度,降低数据库压力并提高响应速度。

通过此实现,用户再次观看视频时将自动从上次停止位置播放,大幅提升用户体验。

相关推荐
一灯架构2 小时前
90%的人答错!一文带你彻底搞懂ArrayList
java·后端
倔强的石头_2 小时前
从 “存得下” 到 “算得快”:工业物联网需要新一代时序数据平台
数据库
Y4090013 小时前
【多线程】线程安全(1)
java·开发语言·jvm
TDengine (老段)3 小时前
TDengine IDMP 可视化 —— 分享
大数据·数据库·人工智能·时序数据库·tdengine·涛思数据·时序数据
布局呆星3 小时前
SpringBoot 基础入门
java·spring boot·spring
风吹迎面入袖凉4 小时前
【Redis】Redisson的可重入锁原理
java·redis
GottdesKrieges4 小时前
OceanBase数据库备份配置
数据库·oceanbase
w6100104664 小时前
cka-2026-ConfigMap
java·linux·cka·configmap
SPC的存折4 小时前
MySQL 8组复制完全指南
linux·运维·服务器·数据库·mysql