diff --git a/src/main/java/com/catcher/core/CommandExecutor.java b/src/main/java/com/catcher/core/CommandExecutor.java deleted file mode 100644 index 0d7f34c..0000000 --- a/src/main/java/com/catcher/core/CommandExecutor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.catcher.core; - -import com.catcher.core.domain.command.Command; - -public interface CommandExecutor { - T run(Command command); -} diff --git a/src/main/java/com/catcher/core/GetCommentCommandExecutor.java b/src/main/java/com/catcher/core/GetCommentCommandExecutor.java deleted file mode 100644 index 72d639f..0000000 --- a/src/main/java/com/catcher/core/GetCommentCommandExecutor.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.catcher.core; - -import com.catcher.core.domain.command.Command; -import com.catcher.core.domain.command.GetParentCommentsByPageCommand; -import com.catcher.core.domain.entity.Comment; -import com.catcher.datasource.CommentRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Component -@RequiredArgsConstructor -public class GetCommentCommandExecutor implements CommandExecutor> { - - private final CommentRepository commentRepository; - - @Override - @Transactional - public Page run(final Command command) { - //1. datasource layer 호출(DB) - //2. 가공해서 넘겨줘야 한다 - return switch (command.getClass().getSimpleName()) { - case "GetParentCommentsByPageCommand" -> getParentCommentsByPage(command); - default -> null; - }; - } - - private Page getParentCommentsByPage(final Command command) { - - final GetParentCommentsByPageCommand getParentCommentsByPageCommand = (GetParentCommentsByPageCommand) command; - return commentRepository.findByParentIsNull(getParentCommentsByPageCommand.getPageable()); - } -} diff --git a/src/main/java/com/catcher/core/PostCommentCommandExecutor.java b/src/main/java/com/catcher/core/PostCommentCommandExecutor.java deleted file mode 100644 index b4ab9ae..0000000 --- a/src/main/java/com/catcher/core/PostCommentCommandExecutor.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.catcher.core; - -import com.catcher.core.domain.command.Command; -import com.catcher.core.domain.command.PostCommentCommand; -import com.catcher.core.domain.command.PostCommentReplyCommand; -import com.catcher.core.domain.entity.Comment; -import com.catcher.datasource.CommentRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Component -@RequiredArgsConstructor -public class PostCommentCommandExecutor implements CommandExecutor { - - private final CommentRepository commentRepository; - - @Override - @Transactional - public Comment run(final Command command) { - //1. datasource layer 호출(DB) - //2. 가공해서 넘겨줘야 한다 - return switch (command.getClass().getSimpleName()) { - case "PostCommentCommand" -> postComment(command); - case "PostCommentReplyCommand" -> postCommentReply(command); - default -> null; - }; - } - - private Comment postComment(final Command command) { - - final PostCommentCommand postCommentCommand = (PostCommentCommand)command; - return commentRepository.save(Comment - .builder() - .userId(postCommentCommand.getUserId()) - .contents(postCommentCommand.getContents()) - .build()); - } - - private Comment postCommentReply(final Command command) { - - final PostCommentReplyCommand postCommentReplyCommand = (PostCommentReplyCommand) command; - - final Comment parentComment = commentRepository - .findById(postCommentReplyCommand.getParentId()) - .orElseThrow(); //TODO: fill custom exception - - final Comment reply = Comment - .builder() - .userId(postCommentReplyCommand.getUserId()) - .parent(parentComment) - .contents(postCommentReplyCommand.getContents()) - .build(); - - parentComment.getReplies().add(reply); - - return reply; - } - -} diff --git a/src/main/java/com/catcher/core/domain/command/Command.java b/src/main/java/com/catcher/core/domain/command/Command.java index 7aa1058..a7498a2 100644 --- a/src/main/java/com/catcher/core/domain/command/Command.java +++ b/src/main/java/com/catcher/core/domain/command/Command.java @@ -1,4 +1,5 @@ package com.catcher.core.domain.command; -public interface Command { +public interface Command { + T execute(); } diff --git a/src/main/java/com/catcher/core/domain/command/CommandExecutor.java b/src/main/java/com/catcher/core/domain/command/CommandExecutor.java new file mode 100644 index 0000000..52290ac --- /dev/null +++ b/src/main/java/com/catcher/core/domain/command/CommandExecutor.java @@ -0,0 +1,5 @@ +package com.catcher.core.domain.command; + +public interface CommandExecutor { + T run(Command command); +} diff --git a/src/main/java/com/catcher/core/domain/command/CommentCommandExecutor.java b/src/main/java/com/catcher/core/domain/command/CommentCommandExecutor.java new file mode 100644 index 0000000..8c7b382 --- /dev/null +++ b/src/main/java/com/catcher/core/domain/command/CommentCommandExecutor.java @@ -0,0 +1,13 @@ +package com.catcher.core.domain.command; + +import org.springframework.stereotype.Component; + +@Component +public class CommentCommandExecutor implements CommandExecutor { + + @Override + public T run(Command command) { + return command.execute(); + } + +} diff --git a/src/main/java/com/catcher/core/domain/command/GetCommentCommand.java b/src/main/java/com/catcher/core/domain/command/GetCommentCommand.java new file mode 100644 index 0000000..7737247 --- /dev/null +++ b/src/main/java/com/catcher/core/domain/command/GetCommentCommand.java @@ -0,0 +1,19 @@ +package com.catcher.core.domain.command; + +import com.catcher.core.domain.entity.Comment; +import com.catcher.core.service.CommentService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@RequiredArgsConstructor +public class GetCommentCommand implements Command> { + + private final CommentService commentService; + + private final Pageable pageable; + @Override + public Page execute() { + return commentService.findByParentIsNull(pageable); + } +} diff --git a/src/main/java/com/catcher/core/domain/command/GetParentCommentsByPageCommand.java b/src/main/java/com/catcher/core/domain/command/GetParentCommentsByPageCommand.java deleted file mode 100644 index b784bc4..0000000 --- a/src/main/java/com/catcher/core/domain/command/GetParentCommentsByPageCommand.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.catcher.core.domain.command; - -import lombok.AllArgsConstructor; -import lombok.Data; -import org.springframework.data.domain.Pageable; - -@Data -@AllArgsConstructor -public class GetParentCommentsByPageCommand implements Command { - - private Pageable pageable; - -} diff --git a/src/main/java/com/catcher/core/domain/command/PostCommentCommand.java b/src/main/java/com/catcher/core/domain/command/PostCommentCommand.java index 2c0c74c..1b30095 100644 --- a/src/main/java/com/catcher/core/domain/command/PostCommentCommand.java +++ b/src/main/java/com/catcher/core/domain/command/PostCommentCommand.java @@ -1,13 +1,21 @@ package com.catcher.core.domain.command; -import lombok.AllArgsConstructor; -import lombok.Data; +import com.catcher.core.domain.request.PostCommentRequest; +import com.catcher.core.service.CommentService; +import lombok.RequiredArgsConstructor; -@Data -@AllArgsConstructor -public class PostCommentCommand implements Command { +@RequiredArgsConstructor +public class PostCommentCommand implements Command { - Long userId; + private final CommentService commentService; + + private final PostCommentRequest postCommentRequest; + + @Override + public Void execute() { + commentService.saveSingleComment(postCommentRequest.getUserId(), postCommentRequest.getContents()); + + return null; + } - String contents; } diff --git a/src/main/java/com/catcher/core/domain/command/PostCommentReplyCommand.java b/src/main/java/com/catcher/core/domain/command/PostCommentReplyCommand.java index 4ff538a..7e13084 100644 --- a/src/main/java/com/catcher/core/domain/command/PostCommentReplyCommand.java +++ b/src/main/java/com/catcher/core/domain/command/PostCommentReplyCommand.java @@ -1,15 +1,25 @@ package com.catcher.core.domain.command; -import lombok.AllArgsConstructor; -import lombok.Data; +import com.catcher.core.domain.request.PostCommentReplyRequest; +import com.catcher.core.service.CommentService; +import lombok.RequiredArgsConstructor; -@Data -@AllArgsConstructor -public class PostCommentReplyCommand implements Command { +@RequiredArgsConstructor +public class PostCommentReplyCommand implements Command { - Long userId; + private final CommentService commentService; - Long parentId; + private final PostCommentReplyRequest postCommentReplyRequest; + + @Override + public Void execute() { + commentService.saveSingleReply( + postCommentReplyRequest.getParentId(), + postCommentReplyRequest.getUserId(), + postCommentReplyRequest.getContents() + ); + + return null; + } - String contents; } diff --git a/src/main/java/com/catcher/core/service/CommentService.java b/src/main/java/com/catcher/core/service/CommentService.java index bce753a..716b922 100644 --- a/src/main/java/com/catcher/core/service/CommentService.java +++ b/src/main/java/com/catcher/core/service/CommentService.java @@ -1,20 +1,48 @@ package com.catcher.core.service; -import com.catcher.core.GetCommentCommandExecutor; -import com.catcher.core.domain.command.GetParentCommentsByPageCommand; import com.catcher.core.domain.entity.Comment; +import com.catcher.datasource.CommentRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class CommentService { - private final GetCommentCommandExecutor getCommentCommandExecutor; + private final CommentRepository commentRepository; - public Page getCommentsWithSize(final Pageable pageable) { - return getCommentCommandExecutor.run(new GetParentCommentsByPageCommand(pageable)); + @Transactional + public Page findByParentIsNull(final Pageable pageable) { + return commentRepository.findByParentIsNull(pageable); + } + + @Transactional + public Comment saveSingleComment(final Long userId, final String contents) { + return commentRepository.save(Comment + .builder() + .userId(userId) + .contents(contents) + .build()); + } + + @Transactional + public Comment saveSingleReply(Long parentId, Long userId, String contents) { + final Comment parentComment = commentRepository + .findById(parentId) + .orElseThrow(); //TODO: fill custom exception + + final Comment reply = Comment + .builder() + .userId(userId) + .parent(parentComment) + .contents(contents) + .build(); + + parentComment.getReplies().add(reply); + + return reply; } } diff --git a/src/main/java/com/catcher/resource/CommentAPiController.java b/src/main/java/com/catcher/resource/CommentAPiController.java index e8b2a61..35dede1 100644 --- a/src/main/java/com/catcher/resource/CommentAPiController.java +++ b/src/main/java/com/catcher/resource/CommentAPiController.java @@ -1,13 +1,13 @@ package com.catcher.resource; -import com.catcher.core.PostCommentCommandExecutor; -import com.catcher.core.domain.command.PostCommentCommand; -import com.catcher.core.domain.command.PostCommentReplyCommand; +import com.catcher.core.domain.command.*; +import com.catcher.core.domain.entity.Comment; import com.catcher.core.domain.request.PostCommentReplyRequest; import com.catcher.core.domain.request.PostCommentRequest; import com.catcher.core.domain.response.GetCommentsByPageResponse; import com.catcher.core.service.CommentService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.*; @@ -19,30 +19,26 @@ @RequestMapping("/comment") public class CommentAPiController { - private final PostCommentCommandExecutor postCommentCommandExecutor; - private final CommentService commentService; + private final CommentCommandExecutor commandExecutor; + @PostMapping public void postComment(@RequestBody PostCommentRequest postCommentRequest) { - postCommentCommandExecutor.run(new PostCommentCommand( - postCommentRequest.getUserId(), - postCommentRequest.getContents()) - ); + Command command = new PostCommentCommand(commentService, postCommentRequest); + commandExecutor.run(command); } @PostMapping("/reply") public void replyComment(@RequestBody PostCommentReplyRequest postCommentReplyRequest) { - postCommentCommandExecutor.run(new PostCommentReplyCommand( - postCommentReplyRequest.getUserId(), - postCommentReplyRequest.getParentId(), - postCommentReplyRequest.getContents() - )); + Command command = new PostCommentReplyCommand(commentService, postCommentReplyRequest); + commandExecutor.run(command); } @GetMapping public List getComments(@PageableDefault(size = 20, sort = {"id"}) Pageable pageable) { - final var commentPage = commentService.getCommentsWithSize(pageable); + Command> command = new GetCommentCommand(commentService, pageable); + Page commentPage = commandExecutor.run(command); return GetCommentsByPageResponse.createGetCommentsByPageResponseList(commentPage); } diff --git a/src/test/java/com/catcher/resource/PostCommentControllerTest.java b/src/test/java/com/catcher/resource/PostCommentControllerTest.java index e458801..82244b9 100644 --- a/src/test/java/com/catcher/resource/PostCommentControllerTest.java +++ b/src/test/java/com/catcher/resource/PostCommentControllerTest.java @@ -1,16 +1,22 @@ package com.catcher.resource; import com.catcher.app.AppApplication; -import com.catcher.core.domain.request.PostCommentReplyRequest; -import com.catcher.datasource.TestCommentRepository; import com.catcher.core.domain.entity.Comment; +import com.catcher.core.domain.request.PostCommentReplyRequest; import com.catcher.core.domain.request.PostCommentRequest; +import com.catcher.core.domain.response.GetCommentsByPageResponse; +import com.catcher.core.service.CommentService; +import com.catcher.datasource.TestCommentRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @@ -18,6 +24,9 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; +import java.util.ArrayList; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -38,6 +47,9 @@ public class PostCommentControllerTest { @Autowired private TestCommentRepository commentRepository; + @Autowired + private CommentService commentService; + @BeforeEach public void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); @@ -107,4 +119,60 @@ public void testPostCommentReply() throws Exception { assertEquals(contents, reply.getContents()); assertEquals(parentComment.getId(), reply.getParent().getId()); } + + @Test + @Transactional + public void 댓글목록조회_테스트_DB조회() { + + // given + Comment parentComment1 = commentService.saveSingleComment(1L, "댓글 작성 테스트1"); + + Comment parentComment2 = commentService.saveSingleComment(2L, "댓글 작성 테스트2"); + + Comment childComment = commentService.saveSingleReply(parentComment1.getId(), 3L, "대댓글 작성 테스트"); + + // when + final var commentList = commentService + .findByParentIsNull(PageRequest.of(0, 2, Sort.Direction.DESC, "id")) + .stream().toList(); + + Comment result1 = commentList.get(0); + Comment result2 = commentList.get(1); + + // then + assertEquals(result1.getId(), parentComment2.getId()); // 내림차순 정렬 확인 + assertEquals(result2.getReplies().get(0).getId(), childComment.getId()); // 대댓글 조회 확인 + } + + @Test + public void 댓글목록조회_테스트_VO생성() { + + // given - 댓글 2개, 1번 댓글에 대댓글 1개, 해당 대댓글에 대대댓글 1개 추가 후 JPA 영속 상태 mocking + Comment parentComment1 = new Comment(1L, null, new ArrayList<>(), 1L, "댓글 작성 테스트1"); + Comment parentComment2 = new Comment(2L, null, new ArrayList<>(), 1L, "댓글 작성 테스트2"); + Comment childComment = new Comment(3L, parentComment1, new ArrayList<>(), 2L, "대댓글 작성 테스트"); + Comment nestedChildComment = new Comment(4L, childComment, new ArrayList<>(), 3L, "대대댓글 작성 테스트"); + parentComment1.getReplies().add(childComment); + childComment.getReplies().add(nestedChildComment); + + Page parentCommentsPage = new PageImpl<>(List.of(parentComment1, parentComment2)); + + // when + List responseVoList = GetCommentsByPageResponse.createGetCommentsByPageResponseList(parentCommentsPage); + GetCommentsByPageResponse result1 = responseVoList.get(0); + GetCommentsByPageResponse result2 = responseVoList.get(1); + GetCommentsByPageResponse childResult = result1.getChildComments().get(0); + GetCommentsByPageResponse nestedChildResult = childResult.getChildComments().get(0); + + // then + assertEquals(result1.getId(), parentComment1.getId()); + assertEquals(result2.getId(), parentComment2.getId()); + assertEquals(result2.getChildComments().size(), 0); + assertEquals(childResult.getId(), childComment.getId()); + assertEquals(nestedChildResult.getId(), nestedChildComment.getId()); + assertEquals(nestedChildResult.getChildComments().size(), 0); + + } + + }