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,230 @@
package com.ycwl.basic.service.mobile;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.video.dto.VideoViewPermissionDTO;
import com.ycwl.basic.model.pc.video.entity.UserVideoViewEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.UserVideoViewRepository;
import com.ycwl.basic.repository.VideoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* 视频查看权限服务
* 处理用户查看vlog视频的权限控制和记录
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class VideoViewPermissionService {
private final UserVideoViewRepository userVideoViewRepository;
private final VideoRepository videoRepository;
private final ScenicRepository scenicRepository;
private final OrderBiz orderBiz;
/**
* 检查并记录用户查看视频
*
* @param userId 用户ID
* @param videoId 视频ID
* @return 查看权限信息
*/
public VideoViewPermissionDTO checkAndRecordView(Long userId, Long videoId) {
try {
// 获取视频信息
VideoEntity video = videoRepository.getVideo(videoId);
if (video == null) {
log.warn("视频不存在: videoId={}", videoId);
return createErrorPermission("视频不存在");
}
Long scenicId = video.getScenicId();
if (scenicId == null) {
log.warn("视频缺少景区信息: videoId={}", videoId);
return createErrorPermission("视频信息不完整");
}
// 检查用户是否已购买
IsBuyRespVO buy = orderBiz.isBuy(userId, scenicId, 0, videoId);
if (buy != null && (buy.isBuy() || buy.isFree())) {
// 已购买,不限制查看
log.debug("用户已购买视频,无查看限制: userId={}, videoId={}", userId, videoId);
return VideoViewPermissionDTO.createUnlimitedPermission(0);
}
// 使用分布式锁执行查看记录操作
VideoViewPermissionDTO result = userVideoViewRepository.executeWithLock(userId, videoId, () -> {
try {
// 获取景区配置
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
// 解析配置参数
Integer vlogViewLimit = scenicConfig.getInteger("vlog_view_limit", 0);
Integer vlogTimeLimit = scenicConfig.getInteger("vlog_time_limit", 0);
// 获取用户查看记录
UserVideoViewEntity viewRecord = userVideoViewRepository.getViewRecord(userId, videoId);
int currentViewCount = 0;
if (viewRecord == null) {
// 首次查看,创建记录
viewRecord = userVideoViewRepository.createViewRecord(userId, videoId, scenicId);
currentViewCount = 1;
} else {
// 增加查看次数
currentViewCount = viewRecord.getViewCount() + 1;
userVideoViewRepository.updateViewCount(userId, videoId, currentViewCount);
}
// 根据配置判断权限
return calculatePermission(currentViewCount, vlogViewLimit, vlogTimeLimit);
} catch (Exception e) {
log.error("检查视频查看权限失败: userId={}, videoId={}", userId, videoId, e);
return createErrorPermission("系统异常,请稍后重试");
}
});
return result != null ? result : createErrorPermission("获取权限信息失败");
} catch (Exception e) {
log.error("检查并记录视频查看失败: userId={}, videoId={}", userId, videoId, e);
return createErrorPermission("系统异常,请稍后重试");
}
}
/**
* 仅检查用户查看权限,不记录查看次数
*
* @param userId 用户ID
* @param videoId 视频ID
* @return 查看权限信息
*/
public VideoViewPermissionDTO checkViewPermission(Long userId, Long videoId) {
try {
// 获取视频信息
VideoEntity video = videoRepository.getVideo(videoId);
if (video == null) {
return createErrorPermission("视频不存在");
}
Long scenicId = video.getScenicId();
if (scenicId == null) {
return createErrorPermission("视频信息不完整");
}
// 检查用户是否已购买
IsBuyRespVO buy = orderBiz.isBuy(userId, scenicId, 0, videoId);
if (buy != null && (buy.isBuy() || buy.isFree())) {
// 已购买,不限制查看
log.debug("用户已购买视频,无查看限制: userId={}, videoId={}", userId, videoId);
return VideoViewPermissionDTO.createUnlimitedPermission(0);
}
// 获取景区配置
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
// 解析配置参数
Integer vlogViewLimit = scenicConfig.getInteger("vlog_view_limit", 0);
Integer vlogTimeLimit = scenicConfig.getInteger("vlog_time_limit", 0);
// 获取用户查看记录
UserVideoViewEntity viewRecord = userVideoViewRepository.getViewRecord(userId, videoId);
int currentViewCount = viewRecord != null ? viewRecord.getViewCount() : 0;
// 根据配置判断权限
return calculatePermission(currentViewCount, vlogViewLimit, vlogTimeLimit);
} catch (Exception e) {
log.error("检查视频查看权限失败: userId={}, videoId={}", userId, videoId, e);
return createErrorPermission("系统异常,请稍后重试");
}
}
/**
* 根据配置计算查看权限
*
* @param currentViewCount 当前查看次数
* @param vlogViewLimit 视频查看次数限制
* @param vlogTimeLimit 时间限制(秒)
* @return 查看权限信息
*/
private VideoViewPermissionDTO calculatePermission(int currentViewCount, Integer vlogViewLimit, Integer vlogTimeLimit) {
// 1. 两个值都为0或负数则为不限制
if ((vlogViewLimit == null || vlogViewLimit <= 0) && (vlogTimeLimit == null || vlogTimeLimit <= 0)) {
return VideoViewPermissionDTO.createUnlimitedPermission(currentViewCount);
}
// 2. vlog_view_limit为0则仅通过vlog_time_limit限制
if (vlogViewLimit == null || vlogViewLimit <= 0) {
if (vlogTimeLimit != null && vlogTimeLimit > 0) {
return VideoViewPermissionDTO.createTimeLimitPermission(currentViewCount, 0, vlogTimeLimit);
} else {
return VideoViewPermissionDTO.createUnlimitedPermission(currentViewCount);
}
}
// 3. vlog_view_limit不为0,判断是否超过次数限制
if (currentViewCount <= vlogViewLimit) {
// 未超过次数限制,可完整查看
return VideoViewPermissionDTO.createFullViewPermission(currentViewCount, vlogViewLimit);
} else {
// 已超过次数限制
if (vlogTimeLimit == null || vlogTimeLimit <= 0) {
// 4. vlog_time_limit为0就不允许查看了
return VideoViewPermissionDTO.createNoPermission(currentViewCount, vlogViewLimit);
} else {
// 通过时间限制查看
return VideoViewPermissionDTO.createTimeLimitPermission(currentViewCount, vlogViewLimit, vlogTimeLimit);
}
}
}
/**
* 解析配置值
*
* @param config 配置Map
* @param key 配置键
* @param defaultValue 默认值
* @return 解析后的值
*/
private Integer parseConfigValue(Map<String, Object> config, String key, Integer defaultValue) {
if (config == null || !config.containsKey(key)) {
return defaultValue;
}
Object value = config.get(key);
if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof String) {
try {
return Integer.valueOf((String) value);
} catch (NumberFormatException e) {
log.warn("配置值解析失败: key={}, value={}, 使用默认值: {}", key, value, defaultValue);
return defaultValue;
}
}
return defaultValue;
}
/**
* 创建错误权限对象
*
* @param message 错误消息
* @return 错误权限对象
*/
private VideoViewPermissionDTO createErrorPermission(String message) {
VideoViewPermissionDTO dto = new VideoViewPermissionDTO();
dto.setCanView(false);
dto.setMessage(message);
return dto;
}
}