You've already forked FrameTour-BE
- 新增视频查看权限相关数据结构和接口 - 实现用户视频查看记录的创建和更新逻辑 - 添加视频查看权限的检查和记录功能 -优化分布式环境下的并发控制
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user