Compare commits

...

2 Commits

Author SHA1 Message Date
曹佳豪
675272f04c 修改视频bug 2025-08-12 09:03:26 +08:00
曹佳豪
32229ab3ef 修改视频bug 2025-08-12 09:02:46 +08:00
14 changed files with 254 additions and 44 deletions

View File

@ -56,7 +56,7 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://82.156.121.2:13306/wzj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
url: jdbc:mysql://82.156.121.2:23306/wzj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: wzj
password: A085F27A43B0
# # 从库数据源

View File

@ -52,7 +52,7 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://82.156.121.2:13306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
url: jdbc:mysql://82.156.121.2:23306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: wzj
password: A085F27A43B0
# # 从库数据源

View File

@ -13,11 +13,11 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
// import org.dromara.common.mybatis.core.page.PageQuery;
// import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.core.constant.HttpStatus;
// import org.dromara.common.core.constant.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -25,7 +25,11 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import com.wzj.soopin.content.utils.RedisOperator;
import com.wzj.soopin.content.service.MsgService;
import com.wzj.soopin.content.domain.base.BaseInfoProperties;
import com.wzj.soopin.content.enums.MessageEnum;
// import com.wzj.soopin.content.domain.po.Comment;
@Slf4j
@Api(tags = "管理端-评论管理接口")
@ -36,6 +40,12 @@ public class CommentController extends BaseController {
@Autowired
private CommentService commentService;
@Autowired
private RedisOperator redis;
@Autowired
private MsgService msgService;
@ApiOperation("获取评论列表")
@PostMapping("/list")
public R<Page<CommentVO>> list(
@ -62,6 +72,51 @@ public class CommentController extends BaseController {
}
}
@ApiOperation("发布评论")
@PostMapping("/publish")
public R<Void> publishComment(@RequestBody CommentBO bo) {
try {
// 鉴权评论人从登录上下文获取覆盖入参
Long loginUserId = LoginHelper.getUserId();
if (loginUserId == null) {
return R.fail("未登录或登录已过期");
}
bo.setCommentUserId(String.valueOf(loginUserId));
// 父评论为空时按根评论处理约定使用"0"作为无父评论标记
if (bo.getFatherCommentId() == null || bo.getFatherCommentId().isEmpty()) {
bo.setFatherCommentId("0");
}
// 1) 创建评论
commentService.createComment(bo);
// 2) 短视频评论总数 +1Redis 优先
redis.increment(BaseInfoProperties.REDIS_VLOG_COMMENT_COUNTS + ":" + bo.getVlogId(), 1);
// 3) 发送站内消息根评论 -> 通知视频作者回复评论 -> 通知被回复用户
if ("0".equals(bo.getFatherCommentId())) {
// 评论视频通知视频作者
if (bo.getVlogerId() != null && !bo.getVlogerId().isEmpty()
&& !String.valueOf(loginUserId).equals(bo.getVlogerId())) {
msgService.createMsg(String.valueOf(loginUserId), bo.getVlogerId(), MessageEnum.COMMENT_VLOG.type, null);
}
} else {
// 回复评论通知父评论作者
Comment father = commentService.getCommentDetail(bo.getFatherCommentId());
if (father != null && father.getCommentUserId() != null
&& !String.valueOf(loginUserId).equals(father.getCommentUserId())) {
msgService.createMsg(String.valueOf(loginUserId), father.getCommentUserId(), MessageEnum.REPLY_YOU.type, null);
}
}
return R.ok();
} catch (Exception e) {
log.error("发布评论失败", e);
return R.fail("发布评论失败: " + e.getMessage());
}
}
@ApiOperation("删除评论")
@PostMapping("/delete")
public R<Void> deleteComment(

View File

@ -131,18 +131,14 @@ public class VlogUploadController extends BaseInfoProperties {
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());
mediaMap.put("title",vlogBO.getTitle());
mediaMap.put("firstFrameImg",vlogBO.getFirstFrameImg());
mediaMap.put("vlogerId",vlogBO.getVlogerId());
// 获取视频统计信息
Map<String, Object> statistics = vlogService.getVlogStatistics(mediaInfo.getFileId());

View File

@ -10,6 +10,13 @@ public class MyListBO {
@Schema(description = "是否公开1公开0私密")
private Integer yesOrNo;
@Schema(description = "页码", defaultValue = "1")
private Long pageNum = 1L;
@Schema(description = "每页大小", defaultValue = "10")
private Long pageSize = 10L;
// getter/setter
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
@ -18,4 +25,10 @@ public class MyListBO {
public Integer getYesOrNo() { return yesOrNo; }
public void setYesOrNo(Integer yesOrNo) { this.yesOrNo = yesOrNo; }
public Long getPageNum() { return pageNum; }
public void setPageNum(Long pageNum) { this.pageNum = pageNum; }
public Long getPageSize() { return pageSize; }
public void setPageSize(Long pageSize) { this.pageSize = pageSize; }
}

View File

@ -33,7 +33,7 @@ public class MessageMO {
@TableField("msgType")
private Integer msgType; // 消息类型 枚举
@TableField("msgContent")
private Map msgContent; // 消息内容
private Map<String, Object> msgContent; // 消息内容
@TableField("createTime")
private Date createTime; // 消息创建时间

View File

@ -25,7 +25,6 @@ public class CommentVO {
private Integer likeCounts;
private String replyedUserNickname;
private LocalDateTime createTime;
private Integer isLike = 0;
private Integer childCount; // 子评论数
private Integer status;
private String vlogerMobile; // 视频作者手机号

View File

@ -18,6 +18,6 @@ public interface MyLikedVlogMapper extends BaseMapperPlus<MyLikedVlog,MyLikedVlo
@Select("SELECT COUNT(*) FROM t_my_liked_vlog WHERE vlog_id = #{vlogId}")
int countLikesByVlogId(@Param("vlogId") String vlogId);
@Select("SELECT u.nickname, u.face, l.created_time FROM t_my_liked_vlog l LEFT JOIN t_users u ON l.user_id = u.id WHERE l.vlog_id = #{vlogId} ORDER BY l.created_time DESC")
@Select("SELECT u.nickname, u.face, l.create_time FROM t_my_liked_vlog l LEFT JOIN t_users u ON l.user_id = u.id WHERE l.vlog_id = #{vlogId} ORDER BY l.create_time DESC")
List<Map<String, Object>> selectLikedUsersByVlogId(@Param("vlogId") String vlogId);
}

View File

@ -1,18 +1,23 @@
package com.wzj.soopin.content.mapper.repository;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.wzj.soopin.content.domain.mo.MessageMO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import java.util.List;
@InterceptorIgnore(tenantLine = "true")
@Mapper
@Repository
public interface MessageRepository {
// 通过实现Repository自定义条件查询
List<MessageMO> findAllByToUserIdEqualsOrderByCreateTimeDesc(String toUserId,
Pageable pageable);
List<MessageMO> findAllByToUserIdEqualsOrderByCreateTimeDesc(@Param("toUserId") String toUserId,
@Param("pageable") Pageable pageable);
void save(MessageMO messageMO);
// void deleteAllByFromUserIdAndToUserIdAndMsgType();
// void deleteAllByFromUserIdAndToUserIdAndMsgType();
}

View File

@ -14,7 +14,7 @@ public interface MsgService {
public void createMsg(String fromUserId,
String toUserId,
Integer type,
Map msgContent);
Map<String, Object> msgContent);
/**
* 查询消息列表

View File

@ -3,13 +3,11 @@ package com.wzj.soopin.content.service.impl;
import com.wzj.soopin.content.domain.base.BaseInfoProperties;
import com.wzj.soopin.content.domain.mo.MessageMO;
import com.wzj.soopin.content.domain.po.Users;
import com.wzj.soopin.content.enums.MessageEnum;
import com.wzj.soopin.content.mapper.repository.MessageRepository;
import com.wzj.soopin.content.service.MsgService;
import com.wzj.soopin.member.domain.po.Member;
import com.wzj.soopin.member.mapper.MemberMapper;
import com.wzj.soopin.member.service.IMemberService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -36,15 +34,18 @@ public class MsgServiceImpl extends BaseInfoProperties implements MsgService {
public void createMsg(String fromUserId,
String toUserId,
Integer type,
Map msgContent) {
Map<String, Object> msgContent) {
Member fromUser = memberMapper.selectById(fromUserId);
MessageMO messageMO = new MessageMO();
messageMO.setFromUserId(fromUserId);
messageMO.setFromNickname(fromUser.getNickname());
messageMO.setFromFace(fromUser.getAvatar());
// 兼容会员资料缺失的情况避免空指针
String fromNickname = fromUser != null && fromUser.getNickname() != null ? fromUser.getNickname() : "";
String fromFace = fromUser != null && fromUser.getAvatar() != null ? fromUser.getAvatar() : "";
messageMO.setFromNickname(fromNickname);
messageMO.setFromFace(fromFace);
messageMO.setToUserId(toUserId);
@ -74,9 +75,9 @@ public class MsgServiceImpl extends BaseInfoProperties implements MsgService {
for (MessageMO msg : list) {
// 如果类型是关注消息则需要查询我之前有没有关注过他用于在前端标记互粉互关
if (msg.getMsgType() != null && msg.getMsgType() == MessageEnum.FOLLOW_YOU.type) {
Map map = msg.getMsgContent();
Map<String, Object> map = (Map<String, Object>) msg.getMsgContent();
if (map == null) {
map = new HashMap();
map = new HashMap<>();
}
String relationship = redis.get(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + msg.getToUserId() + ":" + msg.getFromUserId());

View File

@ -208,7 +208,7 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
List<IndexVlogVO> voList = vlogList.stream().map(v -> {
IndexVlogVO vo = vlogConvert.toVO(v);
if (StringUtils.isNotBlank(userId)) {
vo.setDoIFollowVloger(fansService.queryDoIFollowVloger(Long.valueOf(userId), Long.valueOf(v.getVlogerId())));
vo.setDoIFollowVloger(fansService.queryDoIFollowVloger(userId, v.getVlogerId()));
vo.setDoILikeThisVlog(doILikeVlog(userId, v.getId()));
}
vo.setLikeCounts(getVlogBeLikedCounts(v.getId()));
@ -307,8 +307,29 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
queryWrapper.eq(Vlog::getIsPrivate, bo.getYesOrNo());
Page<Vlog> vlogPage = vlogMapper.selectPage(pageParam, queryWrapper);
List<Vlog> vlogList = vlogPage.getRecords();
// TODO: 组装PagedGridResult返回
return null;
List<IndexVlogVO> voList = vlogList.stream().map(vlog -> {
IndexVlogVO vo = vlogConvert.toVO(vlog);
String uid = bo.getUserId();
if (StringUtils.isBlank(uid)) {
LoginUser user = LoginHelper.getLoginUser();
uid = user != null ? String.valueOf(user.getUserId()) : null;
}
if (StringUtils.isNotBlank(uid)) {
vo.setDoIFollowVloger(fansService.queryDoIFollowVloger(uid, vlog.getVlogerId()));
vo.setDoILikeThisVlog(doILikeVlog(uid, vlog.getId()));
}
vo.setLikeCounts(getVlogBeLikedCounts(vlog.getId()));
vo.setCommentsCounts(getVlogComment(vlog.getId()));
return vo;
}).collect(Collectors.toList());
PagedGridResult gridResult = new PagedGridResult();
gridResult.setRows(voList);
gridResult.setPage(current);
gridResult.setRecords(vlogPage.getTotal());
gridResult.setTotal(vlogPage.getPages());
return gridResult;
}
@Transactional(rollbackFor = Exception.class)
@ -393,8 +414,38 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
queryWrapper.eq(MyLikedVlog::getUserId, bo.getUserId());
Page<MyLikedVlog> likedPage = myLikedVlogMapper.selectPage(pageParam, queryWrapper);
List<MyLikedVlog> likedList = likedPage.getRecords();
// TODO: 组装PagedGridResult返回
return null;
// 组装返回的 VO 列表
String uid = bo.getUserId();
if (StringUtils.isBlank(uid)) {
LoginUser user = LoginHelper.getLoginUser();
uid = user != null ? String.valueOf(user.getUserId()) : null;
}
final String finalUid = uid;
List<IndexVlogVO> voList = likedList.stream()
.map(liked -> {
Vlog vlog = vlogMapper.selectById(liked.getVlogId());
if (vlog == null) {
return null;
}
IndexVlogVO vo = vlogConvert.toVO(vlog);
if (StringUtils.isNotBlank(finalUid)) {
vo.setDoIFollowVloger(fansService.queryDoIFollowVloger(finalUid, vlog.getVlogerId()));
vo.setDoILikeThisVlog(true);
}
vo.setLikeCounts(getVlogBeLikedCounts(vlog.getId()));
vo.setCommentsCounts(getVlogComment(vlog.getId()));
return vo;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
PagedGridResult gridResult = new PagedGridResult();
gridResult.setRows(voList);
gridResult.setPage(current);
gridResult.setRecords(likedPage.getTotal());
gridResult.setTotal(likedPage.getPages());
return gridResult;
}
@Override
@ -445,8 +496,17 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
int likeCounts = myLikedVlogMapper.countLikesByVlogId(vlog.getId());
result.put("likeCounts", likeCounts);
// 评论数
Integer commentCount = commentMapper.countByVlogId(vlog.getId());
// 评论数优先 Redis无则 MySQL
String commentCountStr = redis.get(REDIS_VLOG_COMMENT_COUNTS + ":" + vlog.getId());
Integer commentCount = 0;
if (StringUtils.isNotBlank(commentCountStr)) {
commentCount = Integer.valueOf(commentCountStr);
} else {
commentCount = commentMapper.countByVlogId(vlog.getId());
if (commentCount != null) {
redis.set(REDIS_VLOG_COMMENT_COUNTS + ":" + vlog.getId(), String.valueOf(commentCount));
}
}
result.put("commentCounts", commentCount);
// 获取粉丝数量优先 Redis无则 MySQL
@ -486,7 +546,7 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
// } else {
// result.put("vodDetail", vodDetail);
// }
IndexVlogVO vo = vlogConvert.toVO(vlog);
// 添加评论信息
List<Map<String, Object>> comments = commentMapper.selectCommentsByVlogId(vlog.getId());
result.put("comments", comments);
@ -498,6 +558,7 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
List<Map<String, Object>> likedUsers = myLikedVlogMapper.selectLikedUsersByVlogId(vlog.getId());
result.put("likedUsers", likedUsers);
result.put("vlog",vo);
// 添加粉丝列表
// Page<FansVO> fansPage = fansService.queryMyFans(vlog.getVlogerId(), 0, 10);
@ -618,16 +679,16 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
// 查询所有公开的视频列表
List<Map<String, Object>> allVlogs = vlogMapper.selectAllPublicVlogs();
if (allVlogs != null && !allVlogs.isEmpty()) {
// 从Redis获取每个视频的点赞数量
List<Map<String, Object>> vlogsWithLikeCounts = new ArrayList<>();
for (Map<String, Object> vlog : allVlogs) {
String vlogId = vlog.get("id").toString();
String redisLikeKey = REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId;
String likeCountStr = redis.get(redisLikeKey);
// 获取Redis中的点赞数如果没有则使用数据库中的默认值
int likeCount = 0;
if (likeCountStr != null && !likeCountStr.isEmpty()) {
@ -638,22 +699,22 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService {
likeCount = 0;
}
}
// 添加Redis中的点赞数到视频信息中
vlog.put("redis_like_count", likeCount);
vlogsWithLikeCounts.add(vlog);
}
// 先打乱顺序
Collections.shuffle(vlogsWithLikeCounts);
// 按Redis中的点赞数排序获取前limit个
vlogsWithLikeCounts.sort((v1, v2) -> {
int count1 = (Integer) v1.get("redis_like_count");
int count2 = (Integer) v2.get("redis_like_count");
return Integer.compare(count2, count1); // 降序排列
});
// 取前limit个
List<Map<String, Object>> topLikedVlogs = vlogsWithLikeCounts.stream()
.limit(limit)

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wzj.soopin.content.mapper.repository.MessageRepository">
<!-- 将数据库列映射到 MessageMO 属性 -->
<resultMap id="MessageResultMap" type="com.wzj.soopin.content.domain.mo.MessageMO">
<id column="id" property="id"/>
<result column="from_user_id" property="fromUserId"/>
<result column="from_nickname" property="fromNickname"/>
<result column="from_face" property="fromFace"/>
<result column="to_user_id" property="toUserId"/>
<result column="msg_type" property="msgType"/>
<result column="msg_content" property="msgContent"
typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result column="create_time" property="createTime"/>
</resultMap>
<!-- 保存消息,如果未传 id 则使用 uuid 生成 -->
<insert id="save" parameterType="com.wzj.soopin.content.domain.mo.MessageMO">
INSERT INTO t_message
(
id,
from_user_id,
from_nickname,
from_face,
to_user_id,
msg_type,
msg_content,
create_time
)
VALUES
(
IFNULL(#{id}, REPLACE(UUID(),'-','')),
#{fromUserId},
#{fromNickname},
#{fromFace},
#{toUserId},
#{msgType},
#{msgContent, jdbcType=LONGVARCHAR, typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler},
#{createTime}
)
</insert>
<!-- 按接收人查询,按创建时间倒序,分页 -->
<select id="findAllByToUserIdEqualsOrderByCreateTimeDesc" resultMap="MessageResultMap">
SELECT
id,
from_user_id,
from_nickname,
from_face,
to_user_id,
msg_type,
msg_content,
create_time
FROM t_message
WHERE to_user_id = #{toUserId}
ORDER BY create_time DESC
LIMIT #{pageable.offset}, #{pageable.pageSize}
</select>
</mapper>

View File

@ -143,8 +143,22 @@ public class FansServiceImpl extends ServiceImpl<FansMapper, Fans> implements IF
@Override
public boolean queryDoIFollowVloger(String myId, String vloggerId) {
Fans vlogger = queryFansRelationship(Long.valueOf(myId), Long.valueOf(vloggerId));
return vlogger != null;
try {
// Try to convert string IDs to Long if they are numeric
if (myId != null && vloggerId != null &&
myId.matches("\\d+") && vloggerId.matches("\\d+")) {
Fans vlogger = queryFansRelationship(Long.valueOf(myId), Long.valueOf(vloggerId));
return vlogger != null;
} else {
// If IDs contain non-numeric characters, return false for now
// This prevents the NumberFormatException
log.warn("Cannot convert string IDs to Long: myId={}, vloggerId={}", myId, vloggerId);
return false;
}
} catch (NumberFormatException e) {
log.warn("Failed to convert string IDs to Long: myId={}, vloggerId={}", myId, vloggerId, e);
return false;
}
}
@Override