在Java中实现视频续播功能,通常需要结合后端存储(如数据库)和前端播放器配合。以下是关键步骤和代码示例:
实现思路
-
记录播放进度:播放时定期保存当前播放位置
-
存储进度数据:将进度关联用户/设备ID和视频ID存储
-
恢复播放:再次打开视频时读取上次保存的位置
-
前端配合:播放器跳转到指定时间点
后端实现(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>
关键优化点
-
节流控制 :使用
setTimeout
替代setInterval
避免并发问题 -
本地缓存:可先用localStorage暂存进度,网络恢复后同步到服务器
-
进度验证:后端校验position不超过视频总时长
-
过期策略:超过30天的进度自动清除
-
并发处理:使用@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)
);
扩展场景
-
多端同步:用户在不同设备续播
-
断点续传:结合视频分片技术(HLS/DASH)
-
历史记录:展示所有观看过的视频进度
-
智能续播:超过95%进度视为已完成
提示:实际生产环境中建议使用Redis缓存播放进度,降低数据库压力并提高响应速度。
通过此实现,用户再次观看视频时将自动从上次停止位置播放,大幅提升用户体验。