修改vlog视频后台管理

This commit is contained in:
cjh 2025-06-05 09:57:19 +08:00
parent 2d0e662109
commit 62ce570195
6 changed files with 712 additions and 2 deletions

View File

@ -29,7 +29,11 @@
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
</dependency>
<!--腾讯云短信-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
@ -158,6 +162,26 @@
<artifactId>spring-rabbit</artifactId>
</dependency>
<!-- 腾讯云视频点播SDK -->
<!-- <dependency>-->
<!-- <groupId>com.tencentcloudapi</groupId>-->
<!-- <artifactId>tencentcloud-sdk-java-vod</artifactId>-->
<!-- <version>3.1.1030</version>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 腾讯云SDK公共模块 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.tencentcloudapi</groupId>-->
<!-- <artifactId>tencentcloud-sdk-java-common</artifactId>-->
<!-- <version>3.1.1030</version>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 腾讯云SDK模型模块 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.tencentcloudapi</groupId>-->
<!-- <artifactId>tencentcloud-sdk-java-models</artifactId>-->
<!-- <version>3.1.1030</version>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,201 @@
package com.wzj.soopin.content.controller.admin;
import com.tencentcloudapi.vod.v20180717.models.*;
import com.wzj.soopin.content.result.GraceJSONResult;
import com.wzj.soopin.content.service.VlogUploadService;
import com.wzj.soopin.content.utils.TencentCloudUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
@Slf4j
@Api(tags = "管理端-视频上传接口")
@RequestMapping("admin/vlog/upload")
@RestController
public class VlogUploadController {
@Autowired
private VlogUploadService vlogUploadService;
@Autowired
private TencentCloudUtil tencentCloudUtil;
@ApiOperation("获取腾讯云点播视频列表")
@GetMapping("/list")
public GraceJSONResult getVodList(
@ApiParam(value = "页码", defaultValue = "1") @RequestParam(required = false, defaultValue = "1") Integer pageNum,
@ApiParam(value = "每页记录数", defaultValue = "20") @RequestParam(required = false, defaultValue = "20") Integer pageSize,
@ApiParam(value = "文件状态可选值Normal正常、SystemForbidden平台封禁、Forbidden主动封禁") @RequestParam(required = false) String[] status,
@ApiParam(value = "文件类型可选值Video视频、Audio音频、Image图片") @RequestParam(required = false) String[] categories,
@ApiParam(value = "媒体文件来源可选值Upload上传、Record直播录制") @RequestParam(required = false) String[] sourceTypes,
@ApiParam(value = "媒体文件封装格式mp4、mov等") @RequestParam(required = false) String[] mediaTypes,
@ApiParam(value = "文件名,支持模糊搜索") @RequestParam(required = false) String[] names,
@ApiParam(value = "文件名前缀") @RequestParam(required = false) String[] namePrefixes,
@ApiParam(value = "文件描述,支持模糊搜索") @RequestParam(required = false) String[] descriptions,
@ApiParam(value = "标签") @RequestParam(required = false) String[] tags,
@ApiParam(value = "分类ID") @RequestParam(required = false) Long[] classIds,
@ApiParam(value = "存储地区ap-guangzhou") @RequestParam(required = false) String[] storageRegions,
@ApiParam(value = "创建时间范围-开始时间格式yyyy-MM-dd'T'HH:mm:ss'Z'") @RequestParam(required = false) String createTimeAfter,
@ApiParam(value = "创建时间范围-结束时间格式yyyy-MM-dd'T'HH:mm:ss'Z'") @RequestParam(required = false) String createTimeBefore,
@ApiParam(value = "排序字段目前仅支持CreateTime") @RequestParam(required = false, defaultValue = "CreateTime") String sortField,
@ApiParam(value = "排序方式可选值Desc降序、Asc升序") @RequestParam(required = false, defaultValue = "Desc") String sortOrder,
@ApiParam(value = "需要返回的信息类型可选值basicInfo基础信息、metaData元信息、transcodeInfo转码信息") @RequestParam(required = false) String[] filters) {
try {
// 验证密钥配置
String secretId = tencentCloudUtil.getSecretId();
String secretKey = tencentCloudUtil.getSecretKey();
if (secretId == null || secretId.isEmpty() || secretKey == null || secretKey.isEmpty()) {
log.error("腾讯云密钥未配置");
return GraceJSONResult.errorMsg("腾讯云密钥未配置");
}
// 创建请求对象
SearchMediaRequest req = new SearchMediaRequest();
// 设置分页参数
req.setOffset((long) ((pageNum - 1) * pageSize));
req.setLimit((long) pageSize);
// 设置排序
SortBy sort = new SortBy();
sort.setField(sortField);
sort.setOrder(sortOrder);
req.setSort(sort);
// 设置过滤条件
if (categories != null && categories.length > 0) {
req.setCategories(categories);
}
if (sourceTypes != null && sourceTypes.length > 0) {
req.setSourceTypes(sourceTypes);
}
// if (mediaTypes != null && mediaTypes.length > 0) {
// req.setMediaTypes(mediaTypes);
// }
if (names != null && names.length > 0) {
req.setNames(names);
}
if (namePrefixes != null && namePrefixes.length > 0) {
req.setNamePrefixes(namePrefixes);
}
if (descriptions != null && descriptions.length > 0) {
req.setDescriptions(descriptions);
}
if (tags != null && tags.length > 0) {
req.setTags(tags);
}
if (classIds != null && classIds.length > 0) {
req.setClassIds(classIds);
}
if (storageRegions != null && storageRegions.length > 0) {
req.setStorageRegions(storageRegions);
}
// if (createTimeAfter != null && !createTimeAfter.isEmpty()) {
// req.setCreateTimeAfter(createTimeAfter);
// }
// if (createTimeBefore != null && !createTimeBefore.isEmpty()) {
// req.setCreateTimeBefore(createTimeBefore);
// }
if (filters != null && filters.length > 0) {
req.setFilters(filters);
}
// 调用腾讯云API获取视频列表
log.info("开始调用腾讯云 SearchMedia API");
SearchMediaResponse resp = vlogUploadService.searchMedia(req);
log.info("腾讯云 SearchMedia API 调用成功");
// 处理响应结果
Map<String, Object> result = new HashMap<>();
result.put("totalCount", resp.getTotalCount());
result.put("pageNum", pageNum);
result.put("pageSize", pageSize);
List<Map<String, Object>> mediaList = new ArrayList<>();
if (resp.getMediaInfoSet() != null) {
for (MediaInfo mediaInfo : resp.getMediaInfoSet()) {
Map<String, Object> mediaMap = new HashMap<>();
// 基础信息
MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
mediaMap.put("fileId", mediaInfo.getFileId());
mediaMap.put("name", basicInfo.getName());
mediaMap.put("description", basicInfo.getDescription());
mediaMap.put("createTime", basicInfo.getCreateTime());
mediaMap.put("updateTime", basicInfo.getUpdateTime());
mediaMap.put("expireTime", basicInfo.getExpireTime());
mediaMap.put("classId", basicInfo.getClassId());
mediaMap.put("className", basicInfo.getClassName());
mediaMap.put("classPath", basicInfo.getClassPath());
mediaMap.put("coverUrl", basicInfo.getCoverUrl());
mediaMap.put("type", basicInfo.getType());
mediaMap.put("mediaUrl", basicInfo.getMediaUrl());
mediaMap.put("status", basicInfo.getStatus());
mediaMap.put("storageRegion", basicInfo.getStorageRegion());
mediaMap.put("category", basicInfo.getCategory());
mediaMap.put("storageClass", basicInfo.getStorageClass());
mediaMap.put("tagSet", basicInfo.getTagSet());
mediaList.add(mediaMap);
}
}
result.put("list", mediaList);
return GraceJSONResult.ok(result);
} catch (Exception e) {
log.error("获取视频列表失败", e);
return GraceJSONResult.errorMsg("获取视频列表失败: " + e.getMessage());
}
}
/**
* 视频审核接口
*/
@PostMapping("/audit")
public GraceJSONResult auditVlog(@RequestParam String vlogId,
@RequestParam Integer status,
@RequestParam(required = false) String reason) {
try {
vlogUploadService.auditVlog(vlogId, status, reason);
return GraceJSONResult.ok();
} catch (Exception e) {
log.error("视频审核失败", e);
return GraceJSONResult.errorMsg("视频审核失败: " + e.getMessage());
}
}
/**
* 视频删除接口
*/
@PostMapping("/delete")
public GraceJSONResult deleteVlog(@RequestParam String vlogId) {
try {
vlogUploadService.deleteVlog(vlogId);
return GraceJSONResult.ok();
} catch (Exception e) {
log.error("视频删除失败", e);
return GraceJSONResult.errorMsg("视频删除失败: " + e.getMessage());
}
}
/**
* 视频详情接口
*/
@GetMapping("/detail")
public GraceJSONResult vlogDetail(@RequestParam String vlogId) {
try {
return GraceJSONResult.ok(vlogUploadService.getVlogDetail(vlogId));
} catch (Exception e) {
log.error("获取视频详情失败", e);
return GraceJSONResult.errorMsg("获取视频详情失败: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,42 @@
package com.wzj.soopin.content.service;
import com.tencentcloudapi.vod.v20180717.models.PullUploadRequest;
import com.tencentcloudapi.vod.v20180717.models.PullUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.SearchMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.SearchMediaResponse;
import java.util.Map;
public interface VlogUploadService {
// /**
// * 拉取视频上传
// *
// * @param req 拉取上传请求参数
// * @return 拉取上传响应
// */
// PullUploadResponse pullUpload(PullUploadRequest req) throws Exception;
//
// /**
// * 获取视频上传任务状态
// *
// * @param taskId 任务ID
// * @return 任务状态信息
// */
// Map<String, Object> getTaskStatus(String taskId) throws Exception;
/**
* 搜索媒体文件
*
* @param req 搜索请求
* @return 搜索响应
*/
SearchMediaResponse searchMedia(SearchMediaRequest req);
// 新增视频审核
void auditVlog(String vlogId, Integer status, String reason);
// 新增视频删除
void deleteVlog(String vlogId);
// 新增视频详情
Object getVlogDetail(String vlogId);
}

View File

@ -0,0 +1,243 @@
package com.wzj.soopin.content.service.impl;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DescribeTaskDetailRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeTaskDetailResponse;
import com.tencentcloudapi.vod.v20180717.models.PullUploadRequest;
import com.tencentcloudapi.vod.v20180717.models.PullUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.SearchMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.SearchMediaResponse;
import com.wzj.soopin.content.domain.vo.CommentVO;
import com.wzj.soopin.content.service.VlogUploadService;
import com.wzj.soopin.content.utils.TencentCloudUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class VlogUploadServiceImpl implements VlogUploadService {
@Autowired
private TencentCloudUtil tencentCloudUtil;
@Autowired
private com.wzj.soopin.content.mapper.VlogMapper vlogMapper;
@Autowired
private com.wzj.soopin.content.service.CommentService commentService;
@Autowired
private com.wzj.soopin.content.utils.RedisOperator redis;
@Autowired
private com.wzj.soopin.content.mapper.VlogMapperCustom vlogMapperCustom;
// @Override
// public PullUploadResponse pullUpload(PullUploadRequest req) throws Exception {
// // 获取VOD客户端实例
// VodClient client = tencentCloudUtil.getVodClient();
// // 返回的resp是一个PullUploadResponse的实例与请求对象对应
// return client.PullUpload(req);
// }
@Override
public SearchMediaResponse searchMedia(SearchMediaRequest req) {
try {
// 获取VOD客户端实例
VodClient client = tencentCloudUtil.getVodClient();
// 设置默认值
if (req.getOffset() == null) {
req.setOffset(0L);
}
if (req.getLimit() == null) {
req.setLimit(10L);
}
// 添加日志打印请求参数
// log.info("SearchMediaRequest 请求参数: {}", req.toJsonString());
// 添加调试信息
log.info("请求时间戳: {}", System.currentTimeMillis());
log.info("请求参数详情 - Offset: {}, Limit: {}, Sort: {}, Filters: {}",
req.getOffset(),
req.getLimit(),
// req.getSort() != null ? req.getSort().toJsonString() : "null",
req.getFilters() != null ? String.join(",", req.getFilters()) : "null");
// 验证请求参数
validateSearchRequest(req);
SearchMediaResponse response = client.SearchMedia(req);
log.info("SearchMedia API 调用成功,返回结果数: {}", response.getTotalCount());
return response;
} catch (TencentCloudSDKException e) {
log.error("搜索媒体文件失败: {}", e.getMessage(), e);
// 添加更详细的错误信息
if (e.getMessage().contains("signature")) {
log.error("签名验证失败,请检查:\n1. 密钥是否正确\n2. 服务器时间是否准确\n3. 时区设置是否正确");
} else if (e.getMessage().contains("InvalidParameterValue")) {
log.error("参数值错误,请检查:\n1. 分页参数 Offset 和 Limit 是否有效\n2. 搜索条件是否合法\n3. 排序参数是否正确");
} else if (e.getMessage().contains("UnauthorizedOperation")) {
log.error("未授权操作,请检查:\n1. 密钥是否有权限\n2. 应用 ID 是否正确\n3. 是否开通了点播服务");
}
throw new RuntimeException("搜索媒体文件失败: " + e.getMessage());
}
}
/**
* 验证搜索请求参数
*/
private void validateSearchRequest(SearchMediaRequest req) {
// 验证分页参数
if (req.getOffset() < 0) {
throw new IllegalArgumentException("Offset 不能小于 0");
}
if (req.getLimit() < 1 || req.getLimit() > 50) {
throw new IllegalArgumentException("Limit 必须在 1-50 之间");
}
if (req.getOffset() + req.getLimit() > 5000) {
throw new IllegalArgumentException("Offset + Limit 不能超过 5000");
}
// 验证搜索条件
if (req.getFileIds() != null && req.getFileIds().length > 10) {
throw new IllegalArgumentException("FileIds 数组长度不能超过 10");
}
if (req.getNames() != null && req.getNames().length > 10) {
throw new IllegalArgumentException("Names 数组长度不能超过 10");
}
if (req.getNamePrefixes() != null && req.getNamePrefixes().length > 10) {
throw new IllegalArgumentException("NamePrefixes 数组长度不能超过 10");
}
if (req.getDescriptions() != null && req.getDescriptions().length > 10) {
throw new IllegalArgumentException("Descriptions 数组长度不能超过 10");
}
if (req.getClassIds() != null && req.getClassIds().length > 10) {
throw new IllegalArgumentException("ClassIds 数组长度不能超过 10");
}
if (req.getTags() != null && req.getTags().length > 16) {
throw new IllegalArgumentException("Tags 数组长度不能超过 16");
}
if (req.getSourceTypes() != null && req.getSourceTypes().length > 10) {
throw new IllegalArgumentException("SourceTypes 数组长度不能超过 10");
}
if (req.getStreamIds() != null && req.getStreamIds().length > 10) {
throw new IllegalArgumentException("StreamIds 数组长度不能超过 10");
}
if (req.getStorageRegions() != null && req.getStorageRegions().length > 20) {
throw new IllegalArgumentException("StorageRegions 数组长度不能超过 20");
}
// if (req.getMediaTypes() != null && req.getMediaTypes().length > 10) {
// throw new IllegalArgumentException("MediaTypes 数组长度不能超过 10");
// }
// if (req.getStatus() != null && req.getStatus().length > 10) {
// throw new IllegalArgumentException("Status 数组长度不能超过 10");
// }
// if (req.getReviewResults() != null && req.getReviewResults().length > 10) {
// throw new IllegalArgumentException("ReviewResults 数组长度不能超过 10");
// }
// if (req.getTrtcSdkAppIds() != null && req.getTrtcSdkAppIds().length > 10) {
// throw new IllegalArgumentException("TrtcSdkAppIds 数组长度不能超过 10");
// }
// if (req.getTrtcRoomIds() != null && req.getTrtcRoomIds().length > 10) {
// throw new IllegalArgumentException("TrtcRoomIds 数组长度不能超过 10");
// }
}
// 视频审核
@Override
public void auditVlog(String vlogId, Integer status, String reason) {
// 这里假设 status=1为通过status=2为不通过
// 可根据实际业务调整
// 直接更新数据库状态
// 你可以用 VlogMapper VlogService
// 这里只做伪代码示例
// vlogMapper.updateStatus(vlogId, status, reason);
log.info("审核视频 vlogId={}, status={}, reason={}", vlogId, status, reason);
}
// 视频删除
@Override
public void deleteVlog(String vlogId) {
// 逻辑删除或物理删除
// vlogMapper.deleteById(vlogId);
log.info("删除视频 vlogId={}", vlogId);
}
// 视频详情
@Override
public Object getVlogDetail(String vlogId) {
try {
// 1. 优先从 MySQL 获取视频基础信息
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("vlogId", vlogId);
List<com.wzj.soopin.content.domain.vo.IndexVlogVO> vlogList = vlogMapperCustom.getVlogDetailById(paramMap);
com.wzj.soopin.content.domain.vo.IndexVlogVO vlog = vlogList != null && !vlogList.isEmpty() ? vlogList.get(0) : null;
com.tencentcloudapi.vod.v20180717.models.MediaInfo mediaInfo = null;
if (vlog == null) {
// 若本地无尝试从云点播获取
com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest req = new com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest();
req.setFileIds(new String[]{vlogId});
VodClient client = tencentCloudUtil.getVodClient();
com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse resp = client.DescribeMediaInfos(req);
if (resp.getMediaInfoSet() != null && resp.getMediaInfoSet().length > 0) {
mediaInfo = resp.getMediaInfoSet()[0];
}
}
// 2. 点赞数量优先 Redis无则 MySQL
String likeCountsStr = redis.get(com.wzj.soopin.content.domain.base.BaseInfoProperties.REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId);
int likeCounts;
if (likeCountsStr != null) {
likeCounts = Integer.parseInt(likeCountsStr);
} else if (vlog != null && vlog.getLikeCounts() != null) {
likeCounts = vlog.getLikeCounts();
} else {
likeCounts = 0;
}
// 3. 评论数量优先 Redis无则 MySQL
String commentCountsStr = redis.get(com.wzj.soopin.content.domain.base.BaseInfoProperties.REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId);
int commentCounts;
if (commentCountsStr != null) {
commentCounts = Integer.parseInt(commentCountsStr);
} else if (vlog != null && vlog.getCommentsCounts() != null) {
commentCounts = vlog.getCommentsCounts();
} else {
commentCounts = 0;
}
// 4. 评论内容只查 MySQL
List<com.wzj.soopin.content.domain.vo.CommentVO> commentList = new ArrayList<>();
try {
com.wzj.soopin.content.utils.PagedGridResult pagedGridResult = commentService.queryVlogComments(vlogId, null, 1, 10);
if (pagedGridResult != null && pagedGridResult.getRows() != null) {
@SuppressWarnings("unchecked")
List<com.wzj.soopin.content.domain.vo.CommentVO> tempList = (List<com.wzj.soopin.content.domain.vo.CommentVO>) pagedGridResult.getRows();
if (tempList != null) {
commentList = tempList;
}
}
} catch (Exception e) {
log.warn("获取评论列表失败: {}", e.getMessage());
}
// 5. 统一返回
java.util.Map<String, Object> detail = new java.util.HashMap<>();
detail.put("videoInfo", vlog != null ? vlog : mediaInfo);
detail.put("likeCounts", likeCounts);
detail.put("commentCounts", commentCounts);
detail.put("commentList", commentList);
return detail;
} catch (Exception e) {
log.error("获取视频详情失败", e);
return null;
}
}
}

View File

@ -2,7 +2,6 @@ package com.wzj.soopin.content.utils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
@ -13,9 +12,34 @@ import org.springframework.stereotype.Component;
*/
@Component
@Data
@ConfigurationProperties(prefix = "tencent.cloud")
public class TencentCloudProperties {
/**
* 密钥ID
*/
private String secretId;
/**
* 密钥Key
*/
private String secretKey;
/**
* 区域
*/
private String region;
/**
* 点播配置
*/
private Vod vod = new Vod();
@Data
public static class Vod {
/**
* 应用ID
*/
private String appId;
}
}

View File

@ -0,0 +1,176 @@
package com.wzj.soopin.content.utils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.vod.v20180717.VodClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
/**
* 腾讯云工具类
*/
@Slf4j
@Component
public class TencentCloudUtil {
@Autowired
private TencentCloudProperties properties;
/**
* 获取VOD客户端实例
*
* @return VodClient实例
*/
public VodClient getVodClient() {
// 从配置中获取值
String secretId = properties.getSecretId();
String secretKey = properties.getSecretKey();
String region = properties.getRegion();
String appId = properties.getVod().getAppId();
// 详细的配置检查日志
log.info("开始初始化腾讯云 VOD 客户端");
log.info("配置检查 - SecretId长度: {}, SecretKey长度: {}, Region: {}, AppId: {}",
secretId != null ? secretId.length() : 0,
secretKey != null ? secretKey.length() : 0,
region,
appId);
// 检查密钥格式
if (secretId == null || secretId.isEmpty()) {
throw new IllegalArgumentException("SecretId 不能为空");
}
if (secretKey == null || secretKey.isEmpty()) {
throw new IllegalArgumentException("SecretKey 不能为空");
}
if (region == null || region.isEmpty()) {
throw new IllegalArgumentException("Region 不能为空");
}
// 检查密钥格式
if (secretId.contains(" ")) {
log.warn("SecretId 包含空格,这可能导致签名验证失败");
secretId = secretId.trim();
}
if (secretKey.contains(" ")) {
log.warn("SecretKey 包含空格,这可能导致签名验证失败");
secretKey = secretKey.trim();
}
// 输出服务器时间和时区信息
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
LocalDateTime utcNow = LocalDateTime.now(ZoneId.of("UTC"));
log.info("服务器时间 - 本地: {}, UTC: {}, 时区: {}",
now.format(DateTimeFormatter.ISO_DATE_TIME),
utcNow.format(DateTimeFormatter.ISO_DATE_TIME),
ZoneId.systemDefault().getId());
// 检查密钥编码
try {
byte[] secretIdBytes = secretId.getBytes(StandardCharsets.UTF_8);
byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
// 检查密钥格式
if (secretIdBytes.length != 36) {
log.warn("SecretId 长度异常: {}, 预期长度: 36", secretIdBytes.length);
}
if (secretKeyBytes.length != 64) {
log.warn("SecretKey 长度异常: {}, 预期长度: 64", secretKeyBytes.length);
}
// 检查密钥字符
if (!secretId.matches("^[A-Za-z0-9]+$")) {
log.warn("SecretId 包含非字母数字字符");
}
if (!secretKey.matches("^[A-Za-z0-9]+$")) {
log.warn("SecretKey 包含非字母数字字符");
}
log.info("密钥编码检查 - SecretId UTF-8长度: {}, Base64: {}",
secretIdBytes.length,
Base64.getEncoder().encodeToString(secretIdBytes));
log.info("密钥编码检查 - SecretKey UTF-8长度: {}, Base64: {}",
secretKeyBytes.length,
Base64.getEncoder().encodeToString(secretKeyBytes));
} catch (Exception e) {
log.error("密钥编码检查失败", e);
throw new IllegalArgumentException("密钥编码检查失败: " + e.getMessage());
}
try {
// **添加日志确认Credential和VodClient实例化前使用的实际密钥和AppId**
log.info("实例化 Credential 和 VodClient - SecretId: {}, SecretKey长度: {}, Region: {}, AppId: {}",
secretId != null ? secretId.substring(0, 4) + "****" : "null", // 隐藏部分密钥
secretKey != null ? secretKey.length() : 0,
region,
appId);
// 实例化一个认证对象
Credential cred = new Credential(secretId, secretKey);
// 实例化要请求产品的client对象
VodClient client = new VodClient(cred, region);
log.info("腾讯云 VOD 客户端初始化成功 (地域参数: {})", region);
return client;
} catch (Exception e) {
log.error("初始化腾讯云 VOD 客户端失败", e);
throw new RuntimeException("初始化腾讯云 VOD 客户端失败: " + e.getMessage(), e);
}
}
/**
* 获取密钥ID
*
* @return 密钥ID
*/
public String getSecretId() {
return properties.getSecretId();
}
/**
* 获取密钥Key
*
* @return 密钥Key
*/
public String getSecretKey() {
return properties.getSecretKey();
}
/**
* 获取应用ID
*
* @return 应用ID
*/
public String getAppId() {
return properties.getVod().getAppId();
}
/**
* 获取视频播放地址
*
* @param fileId 视频文件ID
* @return 播放地址
*/
public String getVideoPlayUrl(String fileId) {
// TODO: 实现获取视频播放地址的逻辑
return null;
}
/**
* 获取视频封面地址
*
* @param fileId 视频文件ID
* @return 封面地址
*/
public String getVideoCoverUrl(String fileId) {
// TODO: 实现获取视频封面地址的逻辑
return null;
}
}