You've already forked FrameTour-BE
Compare commits
2 Commits
864fc2c127
...
7a35551a7b
Author | SHA1 | Date | |
---|---|---|---|
7a35551a7b | |||
7820a282d9 |
@@ -1,23 +1,93 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.model.mobile.video.dto.VideoViewPermissionDTO;
|
||||
import com.ycwl.basic.model.task.req.VideoInfoReq;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.service.mobile.VideoViewPermissionService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/video/v1")
|
||||
public class AppVideoController {
|
||||
|
||||
@Autowired
|
||||
private VideoRepository videoRepository;
|
||||
|
||||
@Autowired
|
||||
private VideoViewPermissionService videoViewPermissionService;
|
||||
|
||||
@PostMapping("/{videoId}/updateMeta")
|
||||
public void updateMeta(@PathVariable("videoId") Long videoId, @RequestBody VideoInfoReq req) {
|
||||
videoRepository.updateMeta(videoId, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户查看视频并返回权限信息
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 查看权限信息
|
||||
*/
|
||||
@PostMapping("/{videoId}/recordView")
|
||||
public ApiResponse<VideoViewPermissionDTO> recordView(@PathVariable("videoId") Long videoId) {
|
||||
try {
|
||||
String userIdStr = BaseContextHandler.getUserId();
|
||||
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||
log.warn("用户未登录,无法记录查看: videoId={}", videoId);
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(userIdStr);
|
||||
log.debug("记录用户查看视频: userId={}, videoId={}", userId, videoId);
|
||||
|
||||
VideoViewPermissionDTO permission = videoViewPermissionService.checkAndRecordView(userId, videoId);
|
||||
return ApiResponse.success(permission);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("用户ID格式错误: userId={}, videoId={}", BaseContextHandler.getUserId(), videoId, e);
|
||||
return ApiResponse.fail("用户信息无效");
|
||||
} catch (Exception e) {
|
||||
log.error("记录用户查看视频失败: videoId={}", videoId, e);
|
||||
return ApiResponse.fail("记录查看失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户查看权限(不记录查看次数)
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 查看权限信息
|
||||
*/
|
||||
@GetMapping("/{videoId}/checkPermission")
|
||||
public ApiResponse<VideoViewPermissionDTO> checkPermission(@PathVariable("videoId") Long videoId) {
|
||||
try {
|
||||
String userIdStr = BaseContextHandler.getUserId();
|
||||
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||
log.warn("用户未登录,无法查看权限: videoId={}", videoId);
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(userIdStr);
|
||||
log.debug("检查用户查看权限: userId={}, videoId={}", userId, videoId);
|
||||
|
||||
VideoViewPermissionDTO permission = videoViewPermissionService.checkViewPermission(userId, videoId);
|
||||
return ApiResponse.success(permission);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("用户ID格式错误: userId={}, videoId={}", BaseContextHandler.getUserId(), videoId, e);
|
||||
return ApiResponse.fail("用户信息无效");
|
||||
} catch (Exception e) {
|
||||
log.error("检查用户查看权限失败: videoId={}", videoId, e);
|
||||
return ApiResponse.fail("权限检查失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,119 @@
|
||||
package com.ycwl.basic.model.mobile.video.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 视频查看权限响应DTO
|
||||
* 包含用户查看视频的权限信息和限制详情
|
||||
*/
|
||||
@Data
|
||||
public class VideoViewPermissionDTO {
|
||||
|
||||
/**
|
||||
* 是否可以查看
|
||||
*/
|
||||
@JsonProperty("canView")
|
||||
private Boolean canView;
|
||||
|
||||
/**
|
||||
* 是否无限制查看
|
||||
*/
|
||||
private Boolean isUnlimited;
|
||||
|
||||
/**
|
||||
* 当前查看次数
|
||||
*/
|
||||
private Integer currentViewCount;
|
||||
|
||||
/**
|
||||
* 最大查看次数(0表示无限制)
|
||||
*/
|
||||
private Integer maxViewCount;
|
||||
|
||||
/**
|
||||
* 时间限制(秒,0表示无限制)
|
||||
*/
|
||||
private Integer timeLimit;
|
||||
|
||||
/**
|
||||
* 剩余完整查看次数
|
||||
*/
|
||||
private Integer remainingViews;
|
||||
|
||||
/**
|
||||
* 权限信息描述
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 是否为限时查看模式
|
||||
*/
|
||||
private Boolean isTimeLimitMode;
|
||||
|
||||
public VideoViewPermissionDTO() {
|
||||
this.canView = true;
|
||||
this.isUnlimited = false;
|
||||
this.currentViewCount = 0;
|
||||
this.maxViewCount = 0;
|
||||
this.timeLimit = 0;
|
||||
this.remainingViews = 0;
|
||||
this.isTimeLimitMode = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建无限制查看的权限对象
|
||||
*/
|
||||
public static VideoViewPermissionDTO createUnlimitedPermission(Integer currentViewCount) {
|
||||
VideoViewPermissionDTO dto = new VideoViewPermissionDTO();
|
||||
dto.setCanView(true);
|
||||
dto.setIsUnlimited(true);
|
||||
dto.setCurrentViewCount(currentViewCount);
|
||||
dto.setMessage("无限制查看");
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建完整查看权限对象
|
||||
*/
|
||||
public static VideoViewPermissionDTO createFullViewPermission(Integer currentViewCount, Integer maxViewCount) {
|
||||
VideoViewPermissionDTO dto = new VideoViewPermissionDTO();
|
||||
dto.setCanView(true);
|
||||
dto.setIsUnlimited(false);
|
||||
dto.setCurrentViewCount(currentViewCount);
|
||||
dto.setMaxViewCount(maxViewCount);
|
||||
dto.setRemainingViews(Math.max(0, maxViewCount - currentViewCount));
|
||||
dto.setMessage("完整查看模式,剩余" + dto.getRemainingViews() + "次");
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建限时查看权限对象
|
||||
*/
|
||||
public static VideoViewPermissionDTO createTimeLimitPermission(Integer currentViewCount, Integer maxViewCount, Integer timeLimit) {
|
||||
VideoViewPermissionDTO dto = new VideoViewPermissionDTO();
|
||||
dto.setCanView(true);
|
||||
dto.setIsUnlimited(false);
|
||||
dto.setIsTimeLimitMode(true);
|
||||
dto.setCurrentViewCount(currentViewCount);
|
||||
dto.setMaxViewCount(maxViewCount);
|
||||
dto.setTimeLimit(timeLimit);
|
||||
dto.setRemainingViews(0);
|
||||
dto.setMessage("限时查看模式,每次可查看" + timeLimit + "秒");
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建禁止查看权限对象
|
||||
*/
|
||||
public static VideoViewPermissionDTO createNoPermission(Integer currentViewCount, Integer maxViewCount) {
|
||||
VideoViewPermissionDTO dto = new VideoViewPermissionDTO();
|
||||
dto.setCanView(false);
|
||||
dto.setIsUnlimited(false);
|
||||
dto.setCurrentViewCount(currentViewCount);
|
||||
dto.setMaxViewCount(maxViewCount);
|
||||
dto.setRemainingViews(0);
|
||||
dto.setMessage("已达到查看次数限制,无法继续观看");
|
||||
return dto;
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package com.ycwl.basic.model.pc.video.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户视频查看记录实体
|
||||
* 记录用户查看vlog视频的次数和时间
|
||||
*/
|
||||
@Data
|
||||
@TableName("user_video_view_record")
|
||||
public class UserVideoViewEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 视频ID
|
||||
*/
|
||||
private Long videoId;
|
||||
|
||||
/**
|
||||
* 景区ID
|
||||
*/
|
||||
private Long scenicId;
|
||||
|
||||
/**
|
||||
* 完整查看次数
|
||||
*/
|
||||
private Integer viewCount;
|
||||
|
||||
/**
|
||||
* 最后查看时间
|
||||
*/
|
||||
private Date lastViewTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -963,7 +963,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
// 查询是否触发过低阈值检测
|
||||
String lowThresholdKey = FACE_LOW_THRESHOLD_PFX + faceId;
|
||||
boolean hasLowThreshold = redisTemplate.hasKey(lowThresholdKey);
|
||||
Integer mode = scenicConfig.getInteger("re_match_mode");
|
||||
Integer mode = scenicConfig.getInteger("re_match_mode", 0);
|
||||
return switch (mode) {
|
||||
case 1 -> tourMatch || recognitionCount > 1 || hasLowThreshold;
|
||||
case 5 -> hasLowThreshold || (ruleMatched >= 2);
|
||||
|
Reference in New Issue
Block a user