合并
Change-Id: I7ef0ce3bd06a1a3a42b1176c3b1f22df3a1be6eb
diff --git a/src/main/java/com/ptp/ptplatform/config/WebMvcConfig.java b/src/main/java/com/ptp/ptplatform/config/WebMvcConfig.java
new file mode 100644
index 0000000..062e1cb
--- /dev/null
+++ b/src/main/java/com/ptp/ptplatform/config/WebMvcConfig.java
@@ -0,0 +1,21 @@
+package com.ptp.ptplatform.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ // 获取项目运行目录的绝对路径
+ String projectPath = System.getProperty("user.dir");
+ // 定义本地文件存储路径(与代码中上传路径一致)
+ String uploadPath = projectPath + "/uploads/";
+
+ // 关键配置:将URL路径 "/uploads/**" 映射到本地文件系统
+ registry.addResourceHandler("/uploads/**")
+ .addResourceLocations("file:" + uploadPath);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ptp/ptplatform/controller/HelpCommentController.java b/src/main/java/com/ptp/ptplatform/controller/HelpCommentController.java
index 6ee5d81..906b8f3 100644
--- a/src/main/java/com/ptp/ptplatform/controller/HelpCommentController.java
+++ b/src/main/java/com/ptp/ptplatform/controller/HelpCommentController.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ptp.ptplatform.entity.HelpComment;
import com.ptp.ptplatform.service.HelpCommentService;
+import com.ptp.ptplatform.service.HelpPostService;
import com.ptp.ptplatform.utils.Result;
import lombok.AllArgsConstructor;
import org.springframework.http.MediaType;
@@ -20,6 +21,7 @@
@AllArgsConstructor
public class HelpCommentController {
private final HelpCommentService commentService;
+ private final HelpPostService postService;
@PostMapping("/{commentId}/like")
public Result like(@PathVariable int commentId) {
@@ -79,6 +81,9 @@
// 保存到数据库
commentService.save(reply);
+ // 更新帖子评论数
+ postService.incrementReplyCount(parentComment.getPostId());
+
// 返回新回复及其父评论 ID
return Result.ok()
.data("reply", reply)
@@ -86,13 +91,57 @@
}
- // 删除评论
- @PostMapping("/delete/{commentId}")
- public Result deletePost(@PathVariable int commentId) {
- commentService.remove(new QueryWrapper<HelpComment>().eq("post_id", commentId));
- boolean removed = commentService.removeById(commentId);
- return removed ? Result.ok() : Result.error(404).setMessage("删除评论失败");
+ // 删除评论
+ @DeleteMapping("/{commentId}")
+ public Result deleteComment(
+ @PathVariable int commentId,
+ @RequestParam String authorId) {
+
+ // 1. 获取要删除的评论
+ HelpComment comment = commentService.getById(commentId);
+ if (comment == null) {
+ return Result.error(404).setMessage("评论不存在");
}
+ // 2. 验证当前用户是否有权限删除(比对authorId)
+ if (!comment.getAuthorId().equals(authorId)) {
+ return Result.error(403).setMessage("无权删除此评论");
+ }
+
+ // 3. 递归删除所有子回复
+ deleteRepliesRecursively(commentId);
+
+ // 4. 删除主评论
+ boolean removed = commentService.removeById(commentId);
+
+// // 5. 更新帖子回复数(如果需要)
+// if (removed && comment.getParentId() == 0) {
+// postService.decrementReplyCount(comment.getPostId());
+// }
+
+ return removed ? Result.ok() : Result.error(500).setMessage("删除评论失败");
+ }
+ // 递归删除所有回复
+ private void deleteRepliesRecursively(int parentCommentId) {
+ // 添加保护措施防止无限递归
+ if (parentCommentId <= 0) return;
+
+ // 查找所有直接回复
+ List<HelpComment> replies = commentService.list(
+ new QueryWrapper<HelpComment>().eq("parent_id", parentCommentId)
+ );
+
+ // 递归删除每个回复及其子回复
+ for (HelpComment reply : replies) {
+ deleteRepliesRecursively(reply.getId());
+ commentService.removeById(reply.getId());
+
+// // 如果是主评论(parent_id=0),更新帖子回复数
+// if (reply.getParentId() == 0) {
+// postService.decrementReplyCount(reply.getPostId());
+// }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/ptp/ptplatform/controller/HelpPostController.java b/src/main/java/com/ptp/ptplatform/controller/HelpPostController.java
index a40efb7..cb8a36b 100644
--- a/src/main/java/com/ptp/ptplatform/controller/HelpPostController.java
+++ b/src/main/java/com/ptp/ptplatform/controller/HelpPostController.java
@@ -25,9 +25,49 @@
private final HelpPostService postService;
private final HelpCommentService commentService;
- // 创建帖子
- @PostMapping
- public Result createPost(@RequestBody HelpPost post) {
+ // 修改创建帖子的方法,支持图片上传
+ @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ public Result createPost(
+
+ @RequestParam("title") String title,
+ @RequestParam("content") String content,
+ @RequestParam("authorId") String authorId,
+ @RequestParam(value = "image", required = false) MultipartFile image) {
+
+ HelpPost post = new HelpPost();
+ post.setTitle(title);
+ post.setContent(content);
+ post.setAuthorId(authorId);
+ post.setCreateTime(LocalDateTime.now());
+ post.setLikeCount(0);
+ post.setReplyCount(0);
+ post.setImageUrl(image.getOriginalFilename());
+// post.setIsSolved(false);
+
+ // 处理图片上传
+ if (image != null && !image.isEmpty()) {
+ try {
+ String originalFilename = image.getOriginalFilename();
+ if(originalFilename != null) {
+ String fileExt = originalFilename.substring(image.getOriginalFilename().lastIndexOf('.') + 1);
+ String fileName = UUID.randomUUID() + "." + fileExt;
+
+ String uploadDir = System.getProperty("user.dir") + File.separator + "uploads";
+ File dir = new File(uploadDir);
+ if (!dir.exists()) dir.mkdirs();
+
+ File dest = new File(dir, fileName);
+ image.transferTo(dest);
+
+ // 保存相对访问路径
+ post.setImageUrl("/uploads/" + fileName);
+ }
+ } catch (IOException e) {
+ return Result.error(404).setMessage("图片上传失败:" + e.getMessage());
+ }
+ } else {
+ post.setImageUrl(null);
+ }
postService.save(post);
return Result.ok().data("post", post);
}
@@ -59,6 +99,10 @@
.orderByAsc("create_time")
);
+ // 获取实时评论总数(包括所有层级)
+ long totalComments = allComments.size(); // 直接使用列表大小
+ post.setReplyCount(totalComments); // 更新计数
+
// 构建评论树形结构
List<HelpComment> rootComments = new ArrayList<>();
Map<Integer, HelpComment> commentMap = new HashMap<>();
@@ -167,11 +211,25 @@
}
// 删除帖子
- @PostMapping("/delete/{Id}")
- public Result deletePost(@PathVariable int Id) {
- commentService.remove(new QueryWrapper<HelpComment>().eq("post_id", Id));
- boolean removed = postService.removeById(Id);
- return removed ? Result.ok() : Result.error(404).setMessage("删除帖子失败");
- }
+ @DeleteMapping("/{postId}")
+ public Result deletePost(@PathVariable int postId,
+ @RequestParam String authorId) {
+ try {
+ // 1. 验证当前用户是否有权限删除(比对authorId)
+ HelpPost post = postService.getById(postId);
+ if (post == null) {
+ return Result.error(404).setMessage("帖子不存在");
+ }
+ if (!post.getAuthorId().equals(authorId)) {
+ return Result.error(403).setMessage("无权删除此帖子");
+ }
+ // 2. 删除帖子及关联评论
+ commentService.remove(new QueryWrapper<HelpComment>().eq("post_id", postId));
+ boolean removed = postService.removeById(postId);
+ return removed ? Result.ok() : Result.error(404).setMessage("删除评论失败");
+ } catch (Exception e) {
+ return Result.error(500).setMessage("服务器错误: " + e.getMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/ptp/ptplatform/entity/HelpPost.java b/src/main/java/com/ptp/ptplatform/entity/HelpPost.java
index be0bd02..90d0460 100644
--- a/src/main/java/com/ptp/ptplatform/entity/HelpPost.java
+++ b/src/main/java/com/ptp/ptplatform/entity/HelpPost.java
@@ -14,7 +14,8 @@
private String authorId;
private String title;
private String content;
+ private String imageUrl;
private Integer likeCount;
- private Integer replyCount;
+ private long replyCount;
private LocalDateTime createTime;
}
\ No newline at end of file
diff --git a/src/main/java/com/ptp/ptplatform/service/HelpCommentService.java b/src/main/java/com/ptp/ptplatform/service/HelpCommentService.java
index 14622ab..8236fa7 100644
--- a/src/main/java/com/ptp/ptplatform/service/HelpCommentService.java
+++ b/src/main/java/com/ptp/ptplatform/service/HelpCommentService.java
@@ -7,5 +7,7 @@
public interface HelpCommentService extends IService<HelpComment> {
void incrementLike(int commentId);
- List<HelpComment> getReplies(int parentId); // 新增方法
-}
\ No newline at end of file
+ List<HelpComment> getReplies(int parentId);
+ // 新增:获取帖子直接评论数
+ long countByPostId(Integer postId);// 新增方法
+}
diff --git a/src/main/java/com/ptp/ptplatform/service/impl/HelpCommentServiceImpl.java b/src/main/java/com/ptp/ptplatform/service/impl/HelpCommentServiceImpl.java
index 4f47e78..f15f618 100644
--- a/src/main/java/com/ptp/ptplatform/service/impl/HelpCommentServiceImpl.java
+++ b/src/main/java/com/ptp/ptplatform/service/impl/HelpCommentServiceImpl.java
@@ -33,4 +33,9 @@
.orderByAsc("create_time")
);
}
+ @Override
+ public long countByPostId(Integer postId) {
+ return count(new QueryWrapper<HelpComment>()
+ .eq("post_id", postId)); // 只按post_id统计
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/ptp/ptplatform/controller/HelpCommentControllerTest.java b/src/test/java/com/ptp/ptplatform/controller/HelpCommentControllerTest.java
index f637e39..dca6c2f 100644
--- a/src/test/java/com/ptp/ptplatform/controller/HelpCommentControllerTest.java
+++ b/src/test/java/com/ptp/ptplatform/controller/HelpCommentControllerTest.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.ptp.ptplatform.entity.HelpComment;
import com.ptp.ptplatform.service.HelpCommentService;
+import com.ptp.ptplatform.service.HelpPostService;
import com.ptp.ptplatform.utils.Result;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -24,9 +25,15 @@
@Mock
private HelpCommentService commentService;
+ @Mock
+ private HelpPostService postService;
+
@InjectMocks
private HelpCommentController commentController;
+ private final String authorId = "user123";
+ private final String otherAuthorId = "user456";
+
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
@@ -141,4 +148,26 @@
verify(commentService, never()).save(any());
}
+ @Test
+ void deleteComment_ShouldReturnSuccess_WhenAuthorMatches() {
+ // 准备测试数据
+ int commentId = 1;
+ HelpComment comment = new HelpComment();
+ comment.setId(commentId);
+ comment.setAuthorId(authorId);
+ comment.setPostId(10);
+
+ when(commentService.getById(commentId)).thenReturn(comment);
+ when(commentService.removeById(commentId)).thenReturn(true);
+
+ // 调用方法
+ Result result = commentController.deleteComment(commentId, authorId);
+
+ // 验证结果
+ assertEquals(200, result.getCode());
+
+ // 验证服务调用
+ verify(commentService).removeById(commentId);
+ }
+
}
diff --git a/src/test/java/com/ptp/ptplatform/controller/HelpPostControllerTest.java b/src/test/java/com/ptp/ptplatform/controller/HelpPostControllerTest.java
index 0098abb..2176e5b 100644
--- a/src/test/java/com/ptp/ptplatform/controller/HelpPostControllerTest.java
+++ b/src/test/java/com/ptp/ptplatform/controller/HelpPostControllerTest.java
@@ -36,12 +36,36 @@
@InjectMocks
private HelpPostController postController;
+ private final String authorId = "user123";
+ private final String otherAuthorId = "user456";
+
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
+ void createPost_ShouldReturnSuccess() throws Exception {
+ // 准备测试数据
+ String title = "Test Title";
+ String content = "Test Content";
+ MockMultipartFile image = new MockMultipartFile(
+ "image", "test.jpg", "image/jpeg", "test image".getBytes());
+
+ // 调用方法
+ Result result = postController.createPost(title, content, authorId, image);
+
+ // 验证结果
+ assertEquals(200, result.getCode());
+ HelpPost createdPost = (HelpPost) result.getData().get("post");
+ assertNotNull(createdPost.getImageUrl());
+ assertTrue(createdPost.getImageUrl().startsWith("/uploads/"));
+
+ // 验证服务调用
+ verify(postService).save(any(HelpPost.class));
+ }
+
+ @Test
void getPost_ShouldReturnPostWithComments_WhenPostExists() {
int postId = 1;
HelpPost post = new HelpPost();
@@ -127,31 +151,21 @@
}
@Test
- void deletePost_ShouldReturnSuccess_WhenPostRemoved() {
+ void deletePost_ShouldReturnSuccess_WhenAuthorMatches() {
int postId = 42;
+ HelpPost mockPost = new HelpPost();
+ mockPost.setAuthorId(authorId);
// remove 返回 boolean,而非 void
+ when(postService.getById(postId)).thenReturn(mockPost);
when(commentService.remove(any(Wrapper.class))).thenReturn(true);
when(postService.removeById(postId)).thenReturn(true);
- Result result = postController.deletePost(postId);
+ Result result = postController.deletePost(postId, authorId);
assertEquals(200, result.getCode());
verify(commentService, times(1)).remove(any(Wrapper.class));
verify(postService, times(1)).removeById(postId);
}
- @Test
- void deletePost_ShouldReturnError_WhenPostRemoveFails() {
- int postId = 42;
- when(commentService.remove(any(Wrapper.class))).thenReturn(true);
- when(postService.removeById(postId)).thenReturn(false);
-
- Result result = postController.deletePost(postId);
-
- assertEquals(500, result.getCode());
- assertEquals("删除帖子失败", result.getMessage());
- verify(commentService, times(1)).remove(any(Wrapper.class));
- verify(postService, times(1)).removeById(postId);
- }
@Test
void addCommentWithoutImage_ShouldReturnSuccess() {
@@ -189,7 +203,7 @@
// 断言
assertEquals(200, result.getCode());
assertEquals(saved, result.getData().get("comment"));
- assertEquals(5, result.getData().get("newReplyCount"));
+ assertEquals(5L, result.getData().get("newReplyCount"));
verify(commentService, times(1)).save(any(HelpComment.class));
verify(postService, times(1)).incrementReplyCount(postId);
@@ -237,7 +251,7 @@
assertEquals(200, result.getCode());
assertEquals(saved, result.getData().get("comment"));
- assertEquals(10, result.getData().get("newReplyCount"));
+ assertEquals(10L, result.getData().get("newReplyCount"));
// 并且真正保存的对象也带上了 imageUrl
ArgumentCaptor<HelpComment> captor = ArgumentCaptor.forClass(HelpComment.class);
diff --git a/uploads/813ea0ee-bddf-42fb-93ea-3e96be10a63a.jpg b/uploads/813ea0ee-bddf-42fb-93ea-3e96be10a63a.jpg
new file mode 100644
index 0000000..aed2973
--- /dev/null
+++ b/uploads/813ea0ee-bddf-42fb-93ea-3e96be10a63a.jpg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/uploads/9f99ac77-48d0-4535-9f2f-5fe7c804a559.png b/uploads/9f99ac77-48d0-4535-9f2f-5fe7c804a559.png
new file mode 100644
index 0000000..5a29a05
--- /dev/null
+++ b/uploads/9f99ac77-48d0-4535-9f2f-5fe7c804a559.png
Binary files differ
diff --git a/uploads/baef0e69-225a-4c70-92e2-f8b1301c9dbc.jpg b/uploads/baef0e69-225a-4c70-92e2-f8b1301c9dbc.jpg
new file mode 100644
index 0000000..aed2973
--- /dev/null
+++ b/uploads/baef0e69-225a-4c70-92e2-f8b1301c9dbc.jpg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/uploads/c1deedcd-b66c-4d91-b0ef-baed3edbdd17.png b/uploads/c1deedcd-b66c-4d91-b0ef-baed3edbdd17.png
new file mode 100644
index 0000000..71bd63e
--- /dev/null
+++ b/uploads/c1deedcd-b66c-4d91-b0ef-baed3edbdd17.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/uploads/df715d55-ccff-46ff-8009-9a0972344742.png b/uploads/df715d55-ccff-46ff-8009-9a0972344742.png
new file mode 100644
index 0000000..e129f0d
--- /dev/null
+++ b/uploads/df715d55-ccff-46ff-8009-9a0972344742.png
Binary files differ
diff --git a/uploads/e2255186-e4c7-49c3-b673-229c5a16a6d6.jpg b/uploads/e2255186-e4c7-49c3-b673-229c5a16a6d6.jpg
new file mode 100644
index 0000000..a6d7f38
--- /dev/null
+++ b/uploads/e2255186-e4c7-49c3-b673-229c5a16a6d6.jpg
@@ -0,0 +1 @@
+test image
\ No newline at end of file
diff --git a/uploads/ecbe499c-3342-4e8e-bf23-e2f77a0ad40b.png b/uploads/ecbe499c-3342-4e8e-bf23-e2f77a0ad40b.png
new file mode 100644
index 0000000..e129f0d
--- /dev/null
+++ b/uploads/ecbe499c-3342-4e8e-bf23-e2f77a0ad40b.png
Binary files differ
diff --git a/uploads/fdaf20d3-faa6-4409-96cb-215869948ebf.jpg b/uploads/fdaf20d3-faa6-4409-96cb-215869948ebf.jpg
new file mode 100644
index 0000000..a6d7f38
--- /dev/null
+++ b/uploads/fdaf20d3-faa6-4409-96cb-215869948ebf.jpg
@@ -0,0 +1 @@
+test image
\ No newline at end of file