feat(video): 添加视频查看权限控制功能
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good

- 新增视频查看权限相关数据结构和接口
- 实现用户视频查看记录的创建和更新逻辑
- 添加视频查看权限的检查和记录功能
-优化分布式环境下的并发控制
This commit is contained in:
2025-09-18 18:42:53 +08:00
parent 7820a282d9
commit 7a35551a7b
5 changed files with 645 additions and 1 deletions

View File

@@ -0,0 +1,168 @@
package com.ycwl.basic.repository;
import com.ycwl.basic.model.pc.video.entity.UserVideoViewEntity;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* 用户视频查看记录Repository
* 仅使用Redis存储查看记录
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class UserVideoViewRepository {
private final RedisTemplate<String, String> redisTemplate;
private static final String USER_VIDEO_VIEW_CACHE_KEY = "user_video_view:%s:%s";
private static final String VIEW_RECORD_LOCK_KEY = "view_record_lock:%s:%s";
private static final int CACHE_EXPIRE_HOURS = 72; // 3天过期
private static final int LOCK_EXPIRE_SECONDS = 30;
/**
* 获取用户视频查看记录
*
* @param userId 用户ID
* @param videoId 视频ID
* @return 查看记录
*/
public UserVideoViewEntity getViewRecord(Long userId, Long videoId) {
String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
if (redisTemplate.hasKey(cacheKey)) {
String cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return JacksonUtil.parseObject(cached, UserVideoViewEntity.class);
}
}
return null;
}
/**
* 创建查看记录
*
* @param userId 用户ID
* @param videoId 视频ID
* @param scenicId 景区ID
* @return 查看记录
*/
public UserVideoViewEntity createViewRecord(Long userId, Long videoId, Long scenicId) {
UserVideoViewEntity entity = new UserVideoViewEntity();
entity.setUserId(userId);
entity.setVideoId(videoId);
entity.setScenicId(scenicId);
entity.setViewCount(1);
entity.setLastViewTime(new Date());
entity.setCreateTime(new Date());
entity.setUpdateTime(new Date());
String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
log.debug("创建用户视频查看记录到Redis: userId={}, videoId={}, scenicId={}", userId, videoId, scenicId);
return entity;
}
/**
* 更新查看次数
*
* @param userId 用户ID
* @param videoId 视频ID
* @param viewCount 新的查看次数
* @return 是否更新成功
*/
public boolean updateViewCount(Long userId, Long videoId, Integer viewCount) {
UserVideoViewEntity entity = getViewRecord(userId, videoId);
if (entity != null) {
entity.setViewCount(viewCount);
entity.setLastViewTime(new Date());
entity.setUpdateTime(new Date());
String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
log.debug("更新用户视频查看次数到Redis: userId={}, videoId={}, viewCount={}", userId, videoId, viewCount);
return true;
}
return false;
}
/**
* 增加查看次数(原子操作)
*
* @param userId 用户ID
* @param videoId 视频ID
* @return 是否更新成功
*/
public boolean incrementViewCount(Long userId, Long videoId) {
UserVideoViewEntity entity = getViewRecord(userId, videoId);
if (entity != null) {
entity.setViewCount(entity.getViewCount() + 1);
entity.setLastViewTime(new Date());
entity.setUpdateTime(new Date());
String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
log.debug("增加用户视频查看次数到Redis: userId={}, videoId={}, newCount={}",
userId, videoId, entity.getViewCount());
return true;
}
return false;
}
/**
* 使用Redis分布式锁执行查看记录操作
*
* @param userId 用户ID
* @param videoId 视频ID
* @param operation 操作函数
* @return 操作结果
*/
public <T> T executeWithLock(Long userId, Long videoId, java.util.function.Supplier<T> operation) {
String lockKey = String.format(VIEW_RECORD_LOCK_KEY, userId, videoId);
try {
// 尝试获取锁
Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked",
LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(lockAcquired)) {
try {
return operation.get();
} finally {
// 释放锁
redisTemplate.delete(lockKey);
}
} else {
log.warn("获取查看记录锁失败: userId={}, videoId={}", userId, videoId);
return null;
}
} catch (Exception e) {
log.error("执行查看记录操作失败: userId={}, videoId={}", userId, videoId, e);
return null;
}
}
/**
* 清除缓存
*
* @param userId 用户ID
* @param videoId 视频ID
*/
public void clearCache(Long userId, Long videoId) {
String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
redisTemplate.delete(cacheKey);
}
}