Browse Source

增加动物笔记评论接口

glx_phase2
glx 3 weeks ago
parent
commit
8ee2b6d6cb
  1. 29
      src/main/java/com/youlai/boot/mini/controller/StrayAnimalNoteCommentController.java
  2. 16
      src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalNoteCommentMapper.java
  3. 18
      src/main/java/com/youlai/boot/mini/model/form/DeleteStrayAnimalNoteCommentForm.java
  4. 18
      src/main/java/com/youlai/boot/mini/model/query/AnimalNoteFirstLevelCommentQueryParam.java
  5. 51
      src/main/java/com/youlai/boot/mini/model/vo/AnimalNoteFirstLevelCommentVO.java
  6. 62
      src/main/java/com/youlai/boot/mini/model/vo/AnimalNoteSecondLevelCommentVO.java
  7. 8
      src/main/java/com/youlai/boot/mini/service/StrayAnimalNoteCommentService.java
  8. 85
      src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalNoteCommentServiceImpl.java
  9. 74
      src/main/resources/mapper/mini/MiniStrayAnimalNoteCommentMapper.xml
  10. 2
      src/main/resources/mapper/mini/MiniStrayAnimalNoteMapper.xml

29
src/main/java/com/youlai/boot/mini/controller/StrayAnimalNoteCommentController.java

@ -1,17 +1,23 @@
package com.youlai.boot.mini.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.boot.common.annotation.Log;
import com.youlai.boot.common.annotation.RepeatSubmit;
import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.framework.security.util.SecurityUtils;
import com.youlai.boot.mini.model.form.DeleteStrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.form.StrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.query.AnimalNoteFirstLevelCommentQueryParam;
import com.youlai.boot.mini.model.vo.AnimalNoteFirstLevelCommentVO;
import com.youlai.boot.mini.model.vo.StrayAnimalNoteCommentVO;
import com.youlai.boot.mini.service.StrayAnimalNoteCommentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@Tag(name = "流浪动物笔记评论相关接口")
@ -33,5 +39,28 @@ public class StrayAnimalNoteCommentController {
return Result.success(vo);
}
@Operation(summary = "删除笔记评论接口")
@PostMapping(value = "delete")
@PreAuthorize("isAuthenticated()")
@RepeatSubmit
@Log(module = LogModuleEnum.STRAY_ANIMAL_NOTE_COMMENT, value = ActionTypeEnum.DELETE)
public Result<?> deleteNoteComment(
@Valid @RequestBody DeleteStrayAnimalNoteCommentForm formData
) {
Long userId = SecurityUtils.getUserId();
strayAnimalNoteCommentService.deleteNoteComment(formData, userId);
return Result.success();
}
@Operation(summary = "分页查询笔记一级评论列表接口")
@PostMapping(value = "firstLevel/list")
@Log(module = LogModuleEnum.STRAY_ANIMAL_NOTE_COMMENT, value = ActionTypeEnum.LIST)
public Result<IPage<AnimalNoteFirstLevelCommentVO>> getFirstLevelCommentList(
@Valid @RequestBody AnimalNoteFirstLevelCommentQueryParam queryParam
) {
Long userId = SecurityUtils.getUserId();
IPage<AnimalNoteFirstLevelCommentVO> result = strayAnimalNoteCommentService.getFirstLevelCommentList(queryParam, userId);
return Result.success(result);
}
}

16
src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalNoteCommentMapper.java

@ -1,10 +1,14 @@
package com.youlai.boot.mini.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteComment;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteCommentLike;
import com.youlai.boot.mini.model.query.AnimalNoteFirstLevelCommentQueryParam;
import com.youlai.boot.mini.model.vo.AnimalNoteFirstLevelCommentVO;
import com.youlai.boot.mini.model.vo.AnimalNoteSecondLevelCommentVO;
import org.apache.ibatis.annotations.Param;
/**
import java.util.List;/**
* 流浪动物笔记评论表 Mapper 接口
*
* @author jwy
@ -22,4 +26,12 @@ public interface MiniStrayAnimalNoteCommentMapper extends BaseMapper<MiniStrayAn
String selectUuidById(@Param("id") Long id);
int deleteCommentWithPermissionCheck(@Param("noteUuid") String noteUuid, @Param("commentUuid") String commentUuid, @Param("userId") Long userId);
int decrementCommentCount(@Param("noteId") Long noteId);
IPage<AnimalNoteFirstLevelCommentVO> getFirstLevelComment(IPage<AnimalNoteFirstLevelCommentVO> page, @Param("query") AnimalNoteFirstLevelCommentQueryParam query);
List<MiniStrayAnimalNoteCommentLike> batchGetUserCommentLikes(@Param("noteCommentIds") List<Long> noteCommentIds, @Param("appUserId") Long appUserId);
}

18
src/main/java/com/youlai/boot/mini/model/form/DeleteStrayAnimalNoteCommentForm.java

@ -0,0 +1,18 @@
package com.youlai.boot.mini.model.form;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "删除笔记评论请求参数")
public class DeleteStrayAnimalNoteCommentForm {
@NotBlank(message = "笔记UUID不能为空")
@Schema(description = "笔记UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0677d62d63ec693bf1bd6dab8a877dc1")
private String noteUuid;
@NotBlank(message = "评论UUID不能为空")
@Schema(description = "评论UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0677d62d63ec693bf1bd6dab8a877dc2")
private String commentUuid;
}

18
src/main/java/com/youlai/boot/mini/model/query/AnimalNoteFirstLevelCommentQueryParam.java

@ -0,0 +1,18 @@
package com.youlai.boot.mini.model.query;
import com.youlai.boot.common.base.BaseQuery;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "动物笔记一级评论分页查询参数")
public class AnimalNoteFirstLevelCommentQueryParam extends BaseQuery {
@NotBlank(message = "笔记UUID不能为空")
@Schema(description = "动物笔记UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "0677d62d63ec693bf1bd6dab8a877dc1")
private String noteUUId;
}

51
src/main/java/com/youlai/boot/mini/model/vo/AnimalNoteFirstLevelCommentVO.java

@ -0,0 +1,51 @@
package com.youlai.boot.mini.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
@Data
@Schema(description = "动物笔记一级评论VO")
public class AnimalNoteFirstLevelCommentVO {
@Schema(description = "评论UUID")
private String uuid;
@JsonIgnore
@Schema(hidden = true)
private Long commentId;
@Schema(description = "评论用户UUID")
private String appUserId;
@Schema(description = "评论内容")
private String content;
@Schema(description = "点赞数")
private Long likeCount;
@Schema(description = "二级评论数量")
private Long secondLevelCount;
@Schema(description = "创建时间戳")
private Long createTimestamp;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@Schema(description = "评论用户头像")
private String avatarUrl;
@Schema(description = "评论用户昵称")
private String nickname;
@Schema(description = "是否点赞评论,true点赞,false未点赞")
private Boolean isLiked;
@Schema(description = "评论用户所在省", example = "福建省")
private String province;
}

62
src/main/java/com/youlai/boot/mini/model/vo/AnimalNoteSecondLevelCommentVO.java

@ -0,0 +1,62 @@
package com.youlai.boot.mini.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
@Data
@Schema(description = "动物笔记二级评论VO")
public class AnimalNoteSecondLevelCommentVO {
@Schema(description = "动物笔记uuid")
private String noteUuId;
@Schema(description = "动物笔记评论uuid")
private String uuid;
@Schema(description = "评论用户uuid")
private String miniUserUuId;
@Schema(description = "评论用户头像")
private String avatarUrl;
@Schema(description = "评论用户昵称")
private String nickname;
@Schema(description = "评论内容")
private String content;
@Schema(description = "父评论ID,0为一级评论")
private Long parentId;
@Schema(description = "根评论ID,一级评论为自身ID,二级及以上为所属一级评论ID")
private Long rootId;
@Schema(description = "被回复的用户ID")
private Long replyToUserId;
@Schema(description = "被回复用户头像")
private String replyToAvatarUrl;
@Schema(description = "被回复用户昵称")
private String replyToNickname;
@Schema(description = "点赞数")
private Integer likeCount;
@Schema(description = "创建时间戳")
private Long createTimestamp;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@Schema(description = "是否点赞评论,true点赞,false未点赞")
private Boolean isLiked;
@Schema(description = "评论用户所在省", example = "福建省")
private String province;
}

8
src/main/java/com/youlai/boot/mini/service/StrayAnimalNoteCommentService.java

@ -1,8 +1,12 @@
package com.youlai.boot.mini.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteComment;
import com.youlai.boot.mini.model.form.DeleteStrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.form.StrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.query.AnimalNoteFirstLevelCommentQueryParam;
import com.youlai.boot.mini.model.vo.AnimalNoteFirstLevelCommentVO;
import com.youlai.boot.mini.model.vo.StrayAnimalNoteCommentVO;
import jakarta.validation.Valid;
@ -10,4 +14,8 @@ public interface StrayAnimalNoteCommentService extends IService<MiniStrayAnimalN
StrayAnimalNoteCommentVO addNoteComment(@Valid StrayAnimalNoteCommentForm formData);
void deleteNoteComment(DeleteStrayAnimalNoteCommentForm formData, Long userId);
IPage<AnimalNoteFirstLevelCommentVO> getFirstLevelCommentList(AnimalNoteFirstLevelCommentQueryParam queryParam, Long userId);
}

85
src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalNoteCommentServiceImpl.java

@ -1,7 +1,9 @@
package com.youlai.boot.mini.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.common.exception.MsgException;
import com.youlai.boot.common.util.HttpContext;
@ -12,7 +14,12 @@ import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteCommentMapper;
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteMapper;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNote;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteComment;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteCommentLike;
import com.youlai.boot.mini.model.form.DeleteStrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.form.StrayAnimalNoteCommentForm;
import com.youlai.boot.mini.model.query.AnimalNoteFirstLevelCommentQueryParam;
import com.youlai.boot.mini.model.vo.AnimalNoteFirstLevelCommentVO;
import com.youlai.boot.mini.model.vo.AnimalNoteSecondLevelCommentVO;
import com.youlai.boot.mini.model.vo.StrayAnimalNoteCommentVO;
import com.youlai.boot.mini.service.StrayAnimalNoteCommentService;
import com.youlai.boot.system.mapper.UserMapper;
@ -22,7 +29,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
@ -47,6 +56,39 @@ public class StrayAnimalNoteCommentServiceImpl extends ServiceImpl<MiniStrayAnim
return vo;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteNoteComment(DeleteStrayAnimalNoteCommentForm formData, Long userId) {
// 1. 执行原子删除(带权限校验、存在性校验)
int affectRows = baseMapper.deleteCommentWithPermissionCheck(
formData.getNoteUuid(),
formData.getCommentUuid(),
userId
);
// 2. 删除成功,扣减评论数
if (affectRows == 1) {
Long noteId = miniStrayAnimalNoteMapper.selectIdByUuid(formData.getNoteUuid());
baseMapper.decrementCommentCount(noteId);
return;
}
// 3. 删除失败,查询具体错误原因(仅失败场景执行)
Long noteId = miniStrayAnimalNoteMapper.selectIdByUuid(formData.getNoteUuid());
if (noteId == null) {
throw new MsgException("笔记不存在或已删除");
}
// 查询评论是否存在且属于该笔记
MiniStrayAnimalNoteComment comment = baseMapper.selectParentCommentInfoByUuid(formData.getCommentUuid());
if (comment == null || !comment.getNoteId().equals(noteId)) {
throw new MsgException("评论不存在或已删除");
}
// 剩余情况:权限不足
throw new MsgException("无权限删除该评论");
}
private StrayAnimalNoteCommentVO saveCommentInfo(StrayAnimalNoteCommentForm addCommentForm, Long appUserId) {
// 1. 根据笔记UUID查询ID
Long noteId = miniStrayAnimalNoteMapper.selectIdByUuid(addCommentForm.getStrayAnimalNoteUuId());
@ -156,4 +198,45 @@ public class StrayAnimalNoteCommentServiceImpl extends ServiceImpl<MiniStrayAnim
return animalNoteCommentVO;
}
@Override
@Transactional(readOnly = true, rollbackFor = Exception.class)
public IPage<AnimalNoteFirstLevelCommentVO> getFirstLevelCommentList(AnimalNoteFirstLevelCommentQueryParam queryParam, Long userId) {
// 1. 构造分页参数,默认值兼容
Page<AnimalNoteFirstLevelCommentVO> page = new Page<>(queryParam.getPageNum(), queryParam.getPageSize());
// 2. 查询一级评论分页(SQL已自动统计二级评论数量)
IPage<AnimalNoteFirstLevelCommentVO> result = baseMapper.getFirstLevelComment(page, queryParam);
List<AnimalNoteFirstLevelCommentVO> commentList = result.getRecords();
if (commentList.isEmpty() || userId == null) {
return result;
}
// 3. 提取一级评论内部主键ID(用于查询点赞状态)
List<Long> firstLevelCommentIds = commentList.stream()
.map(AnimalNoteFirstLevelCommentVO::getCommentId)
.collect(Collectors.toList());
// 4. 批量查询登录用户的点赞状态
Map<Long, Boolean> likeStatusMap = Collections.emptyMap();
try {
List<MiniStrayAnimalNoteCommentLike> likeList = baseMapper.batchGetUserCommentLikes(firstLevelCommentIds, userId);
likeStatusMap = likeList.stream()
.collect(Collectors.toMap(
MiniStrayAnimalNoteCommentLike::getNoteCommentId,
like -> Boolean.TRUE,
(v1, v2) -> v1
));
} catch (Exception e) {
log.error("批量查询评论点赞状态失败,用户ID:{}", userId, e);
}
// 5. 给每个评论设置点赞状态
for (AnimalNoteFirstLevelCommentVO comment : commentList) {
Boolean isLiked = likeStatusMap.get(comment.getCommentId());
comment.setIsLiked(Boolean.TRUE.equals(isLiked));
}
return result;
}
}

74
src/main/resources/mapper/mini/MiniStrayAnimalNoteCommentMapper.xml

@ -44,7 +44,7 @@
SELECT id
FROM mini_stray_animal_note_comment
WHERE uuid = #{uuid}
AND deleted = 0
AND is_deleted = 0
LIMIT 1
</select>
@ -53,7 +53,7 @@
SELECT id, note_id, root_id, mini_user_id
FROM mini_stray_animal_note_comment
WHERE uuid = #{uuid}
AND deleted = 0
AND is_deleted = 0
LIMIT 1
</select>
@ -62,8 +62,76 @@
SELECT uuid
FROM mini_stray_animal_note_comment
WHERE id = #{id}
AND deleted = 0
AND is_deleted = 0
LIMIT 1
</select>
<!-- 带权限校验的原子删除评论 -->
<update id="deleteCommentWithPermissionCheck">
UPDATE mini_stray_animal_note_comment c
INNER JOIN mini_stray_animal_note n ON c.note_id = n.id
SET c.is_deleted = 1,
c.update_by = #{userId},
c.update_time = NOW(),
c.update_timestamp = UNIX_TIMESTAMP(NOW(3)) * 1000
WHERE n.uuid = #{noteUuid}
AND c.uuid = #{commentUuid}
AND c.is_deleted = 0
AND n.is_deleted = 0
AND (c.mini_user_id = #{userId} OR n.mini_user_id = #{userId})
</update>
<!-- 扣减笔记评论数(避免负数) -->
<update id="decrementCommentCount">
UPDATE mini_stray_animal_note
SET comment_count = comment_count - 1
WHERE id = #{noteId}
AND comment_count > 0
</update>
<!-- 分页查询一级评论列表(返回UUID+二级评论数量) -->
<select id="getFirstLevelComment" resultType="com.youlai.boot.mini.model.vo.AnimalNoteFirstLevelCommentVO">
SELECT
sanc.id AS commentId,
sanc.uuid AS uuid,
au.uuid AS appUserId,
sanc.content,
sanc.like_count AS likeCount,
sanc.create_timestamp AS createTimestamp,
sanc.create_time AS createTime,
sanc.province,
au.nickname,
au.avatar AS avatarUrl,
<!-- 统计该一级评论下的有效二级评论数量 -->
(SELECT COUNT(*)
FROM mini_stray_animal_note_comment sc
WHERE sc.root_id = sanc.id
AND sc.parent_id != 0
AND sc.is_deleted = 0
) AS secondLevelCount
FROM mini_stray_animal_note_comment sanc
INNER JOIN mini_stray_animal_note note ON sanc.note_id = note.id AND note.uuid = #{query.noteUUId} AND note.is_deleted = 0
LEFT JOIN sys_user au ON sanc.mini_user_id = au.id AND au.is_deleted = 0
WHERE sanc.parent_id = 0
AND sanc.is_deleted = 0
AND sanc.root_id = sanc.id
ORDER BY sanc.like_count DESC, sanc.create_timestamp DESC
</select>
<!-- 批量查询用户对指定评论的点赞状态 -->
<select id="batchGetUserCommentLikes" resultType="com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteCommentLike">
SELECT
note_comment_id,
mini_user_id
FROM
mini_stray_animal_note_comment_like
WHERE
mini_user_id = #{appUserId}
AND note_comment_id IN
<foreach item="noteCommentId" collection="noteCommentIds" open="(" separator="," close=")">
#{noteCommentId}
</foreach>
AND is_deleted = 0
</select>
</mapper>

2
src/main/resources/mapper/mini/MiniStrayAnimalNoteMapper.xml

@ -10,7 +10,7 @@
SELECT id
FROM mini_stray_animal_note
WHERE uuid = #{uuid}
AND deleted = 0
AND is_deleted = 0
LIMIT 1
</select>

Loading…
Cancel
Save