buyer-api/src/main/java/cn/lili/controller/lmk/VideoCommentController.java
New file @@ -0,0 +1,77 @@ package cn.lili.controller.lmk; import cn.lili.group.Update; import cn.lili.group.Add; import org.springframework.validation.annotation.Validated; import org.springframework.security.access.prepost.PreAuthorize; import lombok.RequiredArgsConstructor; import java.util.List; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotEmpty; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import cn.lili.modules.lmk.service.VideoCommentService; import cn.lili.base.Result; import cn.lili.modules.lmk.domain.form.VideoCommentForm; import cn.lili.modules.lmk.domain.query.VideoCommentQuery; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 视频评论 前端控制器 * * @author xp * @since 2025-05-27 */ @Validated @RequiredArgsConstructor @Api(value = "视频评论", tags = "视频评论管理") @RestController @RequestMapping("/buyer/lmk/video-comment") public class VideoCommentController { private final VideoCommentService videoCommentService; @PostMapping("/comment") @ApiOperation(value = "评论", notes = "评论") public Result comment(@RequestBody @Validated(Add.class) VideoCommentForm form) { return videoCommentService.comment(form); } @GetMapping("/wx/page") @ApiOperation(value = "小程序分页", notes = "评论") public Result wxPage(VideoCommentQuery query) { return videoCommentService.wxPage(query); } @DeleteMapping("/{id}") @ApiOperation(value = "ID删除", notes = "ID删除") public Result removeById(@PathVariable("id") String id) { return videoCommentService.removeById(id); } @DeleteMapping("/batch") @ApiOperation(value = "批量删除", notes = "批量删除") public Result remove(@RequestBody @NotEmpty(message = "请选择数据") List<String> ids) { return videoCommentService.remove(ids); } @GetMapping("/page") @ApiOperation(value = "分页", notes = "分页") public Result page(VideoCommentQuery query) { return videoCommentService.page(query); } @GetMapping("/{id}") @ApiOperation(value = "详情", notes = "详情") public Result detail(@PathVariable("id") String id) { return videoCommentService.detail(id); } @GetMapping("/list") @ApiOperation(value = "列表", notes = "列表") public Result list() { return videoCommentService.all(); } } framework/src/main/java/cn/lili/common/sensitive/SensitiveWordsFilter.java
@@ -53,6 +53,17 @@ } /** * 判断内容是否包含敏感词,如果不包含 filter方法会原封不动的返回 * * @param content * @return true:包含 false:不包含 */ public static Boolean includeSentenceWord(String content) { String filter = filter(content, WILDCARD_STAR); return !content.equals(filter); } /** * 对句子进行敏感词过滤<br/> * 如果无敏感词返回输入的sentence对象,即可以用下面的方式判断是否有敏感词:<br/> * framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoComment.java
New file @@ -0,0 +1,56 @@ package cn.lili.modules.lmk.domain.entity; import cn.lili.mybatis.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import lombok.Data; /** * 视频评论 * * @author xp * @since 2025-05-27 */ @Data @TableName("lmk_video_comment") public class VideoComment extends BaseEntity { private static final long serialVersionUID = 1L; @TableField("video_id") /** 视频id */ private String videoId; @TableField("comment_content") /** 评论内容 */ private String commentContent; @TableField("reply_id") /** 回复的评论id */ private String replyId; @TableField("reply_user_id") /** 被回复人id */ private String replyUserId; @TableField("reply_user_nickname") /** 被回复人昵称 */ private String replyUserNickname; @TableField("master_comment_id") /** 主评论id */ private String masterCommentId; @TableField("status") /** 评论状态 */ private String status; @TableField("user_nickname") /** 评论人昵称 */ private String userNickname; @TableField("user_avatar") /** 评论人头像 */ private String userAvatar; } framework/src/main/java/cn/lili/modules/lmk/domain/form/VideoCommentForm.java
New file @@ -0,0 +1,57 @@ package cn.lili.modules.lmk.domain.form; import cn.lili.group.Update; import cn.lili.group.Add; import cn.lili.base.AbsForm; import cn.lili.modules.lmk.domain.entity.VideoComment; import org.springframework.beans.BeanUtils; import javax.validation.constraints.Max; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import org.springframework.lang.NonNull; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; /** * 视频评论表单 * * @author xp * @since 2025-05-27 */ @Data @ApiModel(value = "VideoComment表单", description = "视频评论表单") public class VideoCommentForm extends AbsForm { @NotBlank(message = "视频id不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("视频id") private String videoId; @Max(value = 1000, message = "评论内容过长") @NotBlank(message = "评论内容不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("评论内容") private String commentContent; @ApiModelProperty("回复的评论id") private String replyId; @ApiModelProperty("回复的人") private String replyUserId; @ApiModelProperty("回复的人昵称") private String replyUserNickname; @ApiModelProperty("主评论id,可从reply的评论上获取到") private String masterCommentId; public static VideoComment getEntityByForm(@NonNull VideoCommentForm form, VideoComment entity) { if(entity == null) { entity = new VideoComment(); } BeanUtils.copyProperties(form, entity); return entity; } } framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoCommentQuery.java
New file @@ -0,0 +1,32 @@ package cn.lili.modules.lmk.domain.query; import cn.lili.base.AbsQuery; import java.util.List; import org.springframework.lang.NonNull; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 视频评论查询 * * @author xp * @since 2025-05-27 */ @Data @ApiModel(value = "VideoComment查询参数", description = "视频评论查询参数") public class VideoCommentQuery extends AbsQuery { @ApiModelProperty("视频id") private String videoId; @ApiModelProperty("是否是加载更多子评论,即查子评论分页") private String masterCommentId; @ApiModelProperty(hidden = true) private String replyId; } framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoCommentVO.java
New file @@ -0,0 +1,63 @@ package cn.lili.modules.lmk.domain.vo; import cn.lili.base.AbsVo; import cn.lili.modules.lmk.domain.entity.VideoComment; import java.util.List; import com.baomidou.mybatisplus.annotation.TableField; import org.springframework.lang.NonNull; import org.springframework.beans.BeanUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; /** * 视频评论展示 * * @author xp * @since 2025-05-27 */ @Data @ApiModel(value = "视频评论响应数据", description = "视频评论响应数据") public class VideoCommentVO extends AbsVo { /** 视频id */ @ApiModelProperty("视频id") private String videoId; /** 评论内容 */ @ApiModelProperty("评论内容") private String commentContent; /** 回复的评论id,即parentId */ @ApiModelProperty("回复的评论id") private String replyId; private String replyUserId; private String replyUserNickname; @ApiModelProperty("主评论id") private String masterCommentId; /** 评论状态 */ @ApiModelProperty("评论状态") private String status; @ApiModelProperty("评论人id") private String userId; @ApiModelProperty("评论人昵称") private String userNickname; @ApiModelProperty("评论人头像") private String userAvatar; public static VideoCommentVO getVoByEntity(@NonNull VideoComment entity, VideoCommentVO vo) { if(vo == null) { vo = new VideoCommentVO(); } BeanUtils.copyProperties(entity, vo); return vo; } } framework/src/main/java/cn/lili/modules/lmk/enums/general/VideoCommentStatusEnum.java
New file @@ -0,0 +1,47 @@ package cn.lili.modules.lmk.enums.general; import lombok.Getter; import org.apache.commons.lang3.StringUtils; /** * 视频评论状态 * * @author:xp * @date:2025/5/14 10:30 */ @Getter public enum VideoCommentStatusEnum { NORMAL("normal", "正常"), AUDITING("auditing", "审核中"), INVALID("invalid", "无效的/未通过审核的"), ; private final String value; private final String desc; VideoCommentStatusEnum(String value, String desc) { this.value = value; this.desc = desc; } /** * 获取含义 * * @param value * @return */ public static String getDescByValue(String value) { if (StringUtils.isBlank(value)) { return null; } for (VideoCommentStatusEnum e : VideoCommentStatusEnum.values()){ if (value.equals(e.getValue())) { return e.getDesc(); } } return null; } } framework/src/main/java/cn/lili/modules/lmk/mapper/VideoCommentMapper.java
New file @@ -0,0 +1,50 @@ package cn.lili.modules.lmk.mapper; import cn.lili.modules.lmk.domain.entity.VideoComment; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import cn.lili.modules.lmk.domain.vo.VideoCommentVO; import cn.lili.modules.lmk.domain.form.VideoCommentForm; import cn.lili.modules.lmk.domain.query.VideoCommentQuery; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * 视频评论 Mapper 接口 * * @author xp * @since 2025-05-27 */ @Mapper public interface VideoCommentMapper extends BaseMapper<VideoComment> { /** * id查找视频评论 * @param id * @return */ VideoCommentVO getById(String id); /** * 分页 */ IPage getPage(IPage page, @Param("query") VideoCommentQuery query); /** * 小程序主评论分页查询 * * @param page * @param query * @return */ IPage masterCommentPage(IPage page, @Param("query") VideoCommentQuery query); /** * 小程序回复评论分页查询 * * @param page * @param query */ IPage replyCommentPage(IPage page, @Param("query") VideoCommentQuery query); } framework/src/main/java/cn/lili/modules/lmk/service/VideoCommentService.java
New file @@ -0,0 +1,66 @@ package cn.lili.modules.lmk.service; import cn.lili.modules.lmk.domain.entity.VideoComment; import com.baomidou.mybatisplus.extension.service.IService; import cn.lili.base.Result; import cn.lili.modules.lmk.domain.form.VideoCommentForm; import cn.lili.modules.lmk.domain.query.VideoCommentQuery; import java.util.List; /** * 视频评论 服务类 * * @author xp * @since 2025-05-27 */ public interface VideoCommentService extends IService<VideoComment> { /** * 添加 * @param form * @return */ Result comment(VideoCommentForm form); /** * 批量删除 * @param ids * @return */ Result remove(List<String> ids); /** * id删除 * @param id * @return */ Result removeById(String id); /** * 分页查询 * @param query * @return */ Result page(VideoCommentQuery query); /** * 根据id查找 * @param id * @return */ Result detail(String id); /** * 列表 * @return */ Result all(); /** * 小程序查视频评论 * * @param query * @return */ Result wxPage(VideoCommentQuery query); } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoCommentServiceImpl.java
New file @@ -0,0 +1,147 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; import cn.lili.common.sensitive.SensitiveWordsFilter; import cn.lili.modules.lmk.enums.general.VideoCommentStatusEnum; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.VideoComment; import cn.lili.modules.lmk.mapper.VideoCommentMapper; import cn.lili.modules.lmk.service.VideoCommentService; import cn.lili.base.Result; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.lili.modules.lmk.domain.form.VideoCommentForm; import cn.lili.modules.lmk.domain.vo.VideoCommentVO; import cn.lili.modules.lmk.domain.query.VideoCommentQuery; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; import org.springframework.beans.BeanUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * 视频评论 服务实现类 * * @author xp * @since 2025-05-27 */ @Service @RequiredArgsConstructor public class VideoCommentServiceImpl extends ServiceImpl<VideoCommentMapper, VideoComment> implements VideoCommentService { private final VideoCommentMapper videoCommentMapper; /** * 添加 * @param form * @return */ @Override @Transactional(rollbackFor = Exception.class) public Result comment(VideoCommentForm form) { // 监测内容是否包含敏感词 if (SensitiveWordsFilter.includeSentenceWord(form.getCommentContent())) { return Result.error("评论含敏感内容"); } if (StringUtils.isNotBlank(form.getReplyId())) { VideoComment beReplyComment = baseMapper.selectById(form.getReplyId()); if (Objects.isNull(beReplyComment)) { throw new RuntimeException("您回复的评论已被删除"); } else if (VideoCommentStatusEnum.INVALID.getValue().equals(beReplyComment.getStatus())) { throw new RuntimeException("您回复的评论已失效"); } } VideoComment entity = VideoCommentForm.getEntityByForm(form, null); entity.setStatus(VideoCommentStatusEnum.AUDITING.getValue()); AuthUser currentUser = UserContext.getCurrentUser(); entity.setUserNickname(currentUser.getNickName()); entity.setUserAvatar(currentUser.getFace()); baseMapper.insert(entity); if (StringUtils.isBlank(entity.getReplyId())) { // 不是回复评论,那么就是主评论,主评论的masterId设置为自己的id entity.setMasterCommentId(entity.getId()); } baseMapper.updateById(entity); return Result.ok("添加成功"); } /** * 批量删除 * @param ids * @return */ @Override public Result remove(List<String> ids) { baseMapper.deleteBatchIds(ids); return Result.ok("删除成功"); } /** * id删除 * @param id * @return */ @Override public Result removeById(String id) { baseMapper.deleteById(id); return Result.ok("删除成功"); } /** * 分页查询 * @param query * @return */ @Override public Result page(VideoCommentQuery query) { IPage<VideoCommentVO> page = PageUtil.getPage(query, VideoCommentVO.class); baseMapper.getPage(page, query); return Result.ok().data(page.getRecords()).total(page.getTotal()); } /** * 根据id查找 * @param id * @return */ @Override public Result detail(String id) { VideoCommentVO vo = baseMapper.getById(id); Assert.notNull(vo, "记录不存在"); return Result.ok().data(vo); } /** * 列表 * @return */ @Override public Result all() { List<VideoComment> entities = baseMapper.selectList(null); List<VideoCommentVO> vos = entities.stream() .map(entity -> VideoCommentVO.getVoByEntity(entity, null)) .collect(Collectors.toList()); return Result.ok().data(vos); } @Override public Result wxPage(VideoCommentQuery query) { IPage<VideoCommentVO> page = PageUtil.getPage(query, VideoCommentVO.class); if (StringUtils.isNotBlank(query.getMasterCommentId())) { // 加载子评论的情况 baseMapper.replyCommentPage(page, query); } else { // 加载主评论的情况。主评论id = masterCommentId baseMapper.masterCommentPage(page, query); } return Result.ok().data(page.getRecords()); } } framework/src/main/resources/mapper/lmk/VideoCommentMapper.xml
New file @@ -0,0 +1,105 @@ <?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="cn.lili.modules.lmk.mapper.VideoCommentMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.VideoCommentVO"> <id column="id" property="id"/> <result column="video_id" property="videoId" /> <result column="comment_content" property="commentContent" /> <result column="reply_id" property="replyId" /> <result column="reply_user_id" property="replyUserId" /> <result column="reply_user_nickname" property="replyUserNickname" /> <result column="master_comment_id" property="masterCommentId" /> <result column="status" property="status" /> <result column="create_by" property="userId" /> <result column="user_nickname" property="userNickname" /> <result column="user_avatar" property="userAvatar" /> </resultMap> <select id="getById" resultMap="BaseResultMap"> SELECT LVC.video_id, LVC.comment_content, LVC.reply_id, LVC.master_comment_id, LVC.status, LVC.id FROM lmk_video_comment LVC WHERE LVC.id = #{id} AND LVC.delete_flag = 0 </select> <select id="getPage" resultMap="BaseResultMap"> SELECT LVC.video_id, LVC.comment_content, LVC.reply_id, LVC.master_comment_id, LVC.status, LVC.id FROM lmk_video_comment LVC WHERE LVC.delete_flag = 0 </select> <select id="masterCommentPage" resultMap="BaseResultMap"> SELECT LVC.video_id, LVC.comment_content, LVC.reply_id, LVC.reply_user_id, LVC.reply_user_nickname, LVC.master_comment_id, LVC.status, LVC.id, LVC.create_by, LVC.user_nickname, LVC.user_avatar FROM lmk_video_comment LVC WHERE LVC.id = LVC.master_comment_id AND LVC.video_id = #{query.videoId} AND LVC.status = 'normal' AND LVC.delete_flag = 0 ORDER BY LVC.create_time DESC </select> <select id="replyCommentPage" resultMap="BaseResultMap"> SELECT LVC.video_id, LVC.comment_content, LVC.reply_id, LVC.reply_user_id, LVC.reply_user_nickname, LVC.master_comment_id, LVC.status, LVC.id, LVC.create_by, LVC.user_nickname, LVC.user_avatar FROM lmk_video_comment LVC WHERE LVC.id = LVC.master_comment_id AND LVC.video_id = #{query.videoId} AND LVC.master_comment_id = #{query.masterCommentId} AND LVC.status = 'normal' AND LVC.delete_flag = 0 ORDER BY LVC.create_time ASC </select> </mapper>