comment
Change-Id: Iafdf1c3e19b18faa75e96fde1acad93fda6f77f0
diff --git a/src/main/java/com/example/g8backend/controller/CommentController.java b/src/main/java/com/example/g8backend/controller/CommentController.java
new file mode 100644
index 0000000..353a45d
--- /dev/null
+++ b/src/main/java/com/example/g8backend/controller/CommentController.java
@@ -0,0 +1,35 @@
+package com.example.g8backend.controller;
+
+import com.example.g8backend.entity.Comment;
+import com.example.g8backend.service.ICommentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/comments")
+public class CommentController {
+
+ @Autowired
+ private ICommentService commentService;
+
+ // 创建评论
+ @PostMapping
+ public void createComment(@RequestParam Long postId, @RequestParam Long userId,
+ @RequestParam String content, @RequestParam(required = false) Long parentCommentId) {
+ commentService.createComment(postId, userId, content, parentCommentId);
+ }
+
+ // 获取某帖子下的所有评论,包括顶级评论及其子评论
+ @GetMapping("/post/{postId}")
+ public List<Comment> getCommentsByPostId(@PathVariable Long postId) {
+ return commentService.getCommentsByPostId(postId);
+ }
+
+ // 删除评论
+ @DeleteMapping("/{commentId}")
+ public void deleteComment(@PathVariable Long commentId) {
+ commentService.deleteComment(commentId);
+ }
+}
diff --git a/src/main/java/com/example/g8backend/dto/CommentDTO.java b/src/main/java/com/example/g8backend/dto/CommentDTO.java
new file mode 100644
index 0000000..d36e748
--- /dev/null
+++ b/src/main/java/com/example/g8backend/dto/CommentDTO.java
@@ -0,0 +1,12 @@
+package com.example.g8backend.dto;
+
+import java.util.List;
+
+public class CommentDTO {
+ private Long commentId;
+ private Long userId;
+ private String content;
+ private List<CommentDTO> replies;
+
+ // Getter and Setter
+}
diff --git a/src/main/java/com/example/g8backend/entity/Comment.java b/src/main/java/com/example/g8backend/entity/Comment.java
new file mode 100644
index 0000000..30fa763
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/Comment.java
@@ -0,0 +1,73 @@
+package com.example.g8backend.entity;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+public class Comment {
+ private Long commentId; // 评论ID
+ private Long postId; // 所属帖子ID
+ private Long userId; // 评论用户ID
+ private String content; // 评论内容
+ private Long parentCommentId; // 父评论ID,如果是顶级评论则为NULL
+ private Timestamp createdAt; // 评论时间
+
+ private List<Comment> replies;
+
+ // Getter and Setter
+ public Long getCommentId() {
+ return commentId;
+ }
+
+ public void setCommentId(Long commentId) {
+ this.commentId = commentId;
+ }
+
+ public Long getPostId() {
+ return postId;
+ }
+
+ public void setPostId(Long postId) {
+ this.postId = postId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public Long getParentCommentId() {
+ return parentCommentId;
+ }
+
+ public void setParentCommentId(Long parentCommentId) {
+ this.parentCommentId = parentCommentId;
+ }
+
+ public Timestamp getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Timestamp createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ // Getter and Setter for replies
+ public List<Comment> getReplies() {
+ return replies;
+ }
+
+ public void setReplies(List<Comment> replies) {
+ this.replies = replies;
+ }
+}
diff --git a/src/main/java/com/example/g8backend/mapper/CommentMapper.java b/src/main/java/com/example/g8backend/mapper/CommentMapper.java
new file mode 100644
index 0000000..b8fa1bf
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/CommentMapper.java
@@ -0,0 +1,26 @@
+package com.example.g8backend.mapper;
+
+import com.example.g8backend.entity.Comment;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface CommentMapper {
+
+ // 插入评论
+ @Insert("INSERT INTO comments (post_id, user_id, content, parent_comment_id) VALUES (#{postId}, #{userId}, #{content}, #{parentCommentId})")
+ int insert(Comment comment);
+
+ // 获取顶级评论
+ @Select("SELECT * FROM comments WHERE post_id = #{postId} AND parent_comment_id IS NULL ORDER BY created_at DESC")
+ List<Comment> findTopLevelCommentsByPostId(Long postId);
+
+ // 获取某个父评论ID对应的子评论
+ @Select("SELECT * FROM comments WHERE parent_comment_id = #{parentCommentId} ORDER BY created_at DESC")
+ List<Comment> findRepliesByParentCommentId(Long parentCommentId);
+
+ // 删除评论
+ @Delete("DELETE FROM comments WHERE comment_id = #{commentId}")
+ int deleteById(Long commentId);
+}
diff --git a/src/main/java/com/example/g8backend/service/ICommentService.java b/src/main/java/com/example/g8backend/service/ICommentService.java
new file mode 100644
index 0000000..ea82f8f
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/ICommentService.java
@@ -0,0 +1,16 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.Comment;
+
+import java.util.List;
+
+public interface ICommentService {
+
+ void createComment(Long postId, Long userId, String content, Long parentCommentId);
+
+ List<Comment> getCommentsByPostId(Long postId);
+
+ List<Comment> getReplies(Long parentCommentId, int depth);
+
+ boolean deleteComment(Long commentId);
+}
diff --git a/src/main/java/com/example/g8backend/service/impl/CommentServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/CommentServiceImpl.java
new file mode 100644
index 0000000..fae8a1f
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/impl/CommentServiceImpl.java
@@ -0,0 +1,70 @@
+package com.example.g8backend.service.impl;
+
+import com.example.g8backend.entity.Comment;
+import com.example.g8backend.mapper.CommentMapper;
+import com.example.g8backend.service.ICommentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Service
+public class CommentServiceImpl implements ICommentService {
+
+ @Autowired
+ private CommentMapper commentMapper;
+
+ @Override
+ public void createComment(Long postId, Long userId, String content, Long parentCommentId) {
+ Comment comment = new Comment();
+ comment.setPostId(postId);
+ comment.setUserId(userId);
+ comment.setContent(content);
+ comment.setParentCommentId(parentCommentId); // 如果是顶级评论为NULL
+ commentMapper.insert(comment);
+ }
+
+ @Override
+// 获取帖子下的所有评论(顶级评论及其子评论)
+ public List<Comment> getCommentsByPostId(Long postId) {
+ // 获取顶级评论
+ List<Comment> topLevelComments = commentMapper.findTopLevelCommentsByPostId(postId);
+
+ // 获取每个评论的子评论
+ for (Comment comment : topLevelComments) {
+ List<Comment> replies = getReplies(comment.getCommentId(), 0); // 初始深度为0
+ comment.setReplies(replies); // 设置子评论
+ }
+
+ return topLevelComments;
+ }
+
+
+ // 获取某个评论的子评论,并设置递归深度
+ public List<Comment> getReplies(Long parentCommentId, int depth) {
+ // 如果递归深度超过最大限制,停止递归
+ if (depth > 5) {
+ return new ArrayList<>();
+ }
+
+ // 获取当前评论的子评论
+ List<Comment> replies = commentMapper.findRepliesByParentCommentId(parentCommentId);
+
+ // 遍历每个子评论
+ for (Comment reply : replies) {
+ // 递归获取该子评论的子评论
+ List<Comment> childReplies = getReplies(reply.getCommentId(), depth + 1); // 深度加1
+ reply.setReplies(childReplies); // 设置该子评论的子评论
+ }
+
+ return replies;
+ }
+
+
+ @Override
+ public boolean deleteComment(Long commentId) {
+ return commentMapper.deleteById(commentId) > 0;
+ }
+}
diff --git a/src/test/java/com/example/g8backend/service/CommentServiceTest.java b/src/test/java/com/example/g8backend/service/CommentServiceTest.java
new file mode 100644
index 0000000..f76880a
--- /dev/null
+++ b/src/test/java/com/example/g8backend/service/CommentServiceTest.java
@@ -0,0 +1,125 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.Comment;
+import com.example.g8backend.mapper.CommentMapper;
+import com.example.g8backend.service.impl.CommentServiceImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(SpringExtension.class)
+@DisplayName("评论服务测试")
+class CommentServiceTest {
+
+ @Mock
+ private CommentMapper commentMapper;
+
+ @InjectMocks
+ private CommentServiceImpl commentService;
+
+ private Comment testComment;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ testComment = createTestComment();
+ }
+
+ private Comment createTestComment() {
+ Comment comment = new Comment();
+ comment.setCommentId(1L);
+ comment.setPostId(1L);
+ comment.setUserId(1L);
+ comment.setContent("测试评论内容");
+ return comment;
+ }
+
+ @Test
+ @DisplayName("创建评论-成功")
+ void createComment_ShouldSucceed() {
+ // Arrange
+ when(commentMapper.insert(any(Comment.class))).thenReturn(1);
+
+ // Act
+ commentService.createComment(1L, 1L, "测试评论内容", null);
+
+ // Assert
+ verify(commentMapper).insert(any(Comment.class));
+ }
+
+ @Test
+ @DisplayName("获取评论-根据帖子ID返回评论列表")
+ void getCommentsByPostId_ShouldReturnComments() {
+ // Arrange
+ List<Comment> expectedComments = Arrays.asList(testComment);
+ when(commentMapper.findTopLevelCommentsByPostId(1L)).thenReturn(expectedComments);
+
+ // Act
+ List<Comment> result = commentService.getCommentsByPostId(1L);
+
+ // Assert
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ assertEquals(testComment.getCommentId(), result.get(0).getCommentId());
+ verify(commentMapper).findTopLevelCommentsByPostId(1L);
+ }
+
+ @Test
+ @DisplayName("删除评论-成功")
+ void deleteComment_ShouldSucceed() {
+ // Arrange
+ when(commentMapper.deleteById(1L)).thenReturn(1);
+
+ // Act
+ boolean result = commentService.deleteComment(1L);
+
+ // Assert
+ assertTrue(result);
+ verify(commentMapper).deleteById(1L);
+ }
+
+ @Test
+ @DisplayName("获取评论-没有评论")
+ void getCommentsByPostId_WhenNoComments_ShouldReturnEmptyList() {
+ // Arrange
+ when(commentMapper.findTopLevelCommentsByPostId(999L)).thenReturn(Arrays.asList());
+
+ // Act
+ List<Comment> result = commentService.getCommentsByPostId(999L);
+
+ // Assert
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ verify(commentMapper).findTopLevelCommentsByPostId(999L);
+ }
+
+ @Test
+ @DisplayName("获取评论-根据父评论ID返回子评论")
+ void getReplies_ShouldReturnReplies() {
+ // Arrange
+ List<Comment> expectedReplies = Arrays.asList(testComment);
+ when(commentMapper.findRepliesByParentCommentId(1L)).thenReturn(expectedReplies);
+
+ // Act
+ List<Comment> result = commentService.getReplies(1L, 5);
+
+ // Assert
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ assertEquals(testComment.getCommentId(), result.get(0).getCommentId());
+ verify(commentMapper).findRepliesByParentCommentId(1L);
+ }
+
+}