저번 글에서 해시태그 검색 기능까지 구현하였다.
일반적인 게시판이면 게시글들을 쓰면 거기에 댓글을 달 수가 있다. 구현해보도록 하겠습니다.
ArticleCommentController
RequiredArgsConstructor
@RequestMapping("/comments")
@Controller
public class ArticleCommentController {
private final ArticleCommentService articleCommentService;
@PostMapping("/new")
public String postNewArticleComment(ArticleCommentRequest articleCommentRequest) {
articleCommentService.saveArticleComment(articleCommentRequest.toDto(UserAccountDto.of(
"jisu", "1234", "jisu@email.com", null, null
)));
return "redirect:/articles/" + articleCommentRequest.getArticleId();
}
@PostMapping("/{commentId}/delete")
public String deleteArticleComment(@PathVariable long commentId, long articleId) {
articleCommentService.deleteArticleComment(commentId);
return "redirect:/articles/" + articleId;
}
}
@PostMappint("/new") 는 새로운 댓글을 작성하는 메소드입니다.
현재 인증기능이 구현되지 않았으므로 하드코딩으로 UsersAccount 엔티티의 값을 넣어줍니다.
그 후의 articleCommentRequest에서 게시글 id를 가져와 다시 리턴해줍니다.
@PostMapping("/{commentId}/delete")
댓글을 삭제하는 메소드 url 입니다.
ArticleCommentDto
public static ArticleCommentDto of(Long articleId, UserAccountDto userAccountDto, String content) {
return new ArticleCommentDto(null, articleId, userAccountDto, content, null, null, null, null);
}
public ArticleComment toEntity(Article article, UserAccount userAccount) {
return ArticleComment.of(
article,
userAccount,
content
);
}
두개의 메소드를 추가해줍니다.
of는 정적팩토리 메소드로 ArticleCommentDto객체를 리턴해줍니다.
toEntity 메소드는 댓글엔티티 == ArticleComment 를 repository로 넘길때 엔티티를 리턴해주는 역할을 합니다.
ArticleCommentRequest
@Data
public class ArticleCommentRequest {
private final Long articleId;
private final String content;
public static ArticleCommentRequest of(Long articleId, String content) {
return new ArticleCommentRequest(articleId, content);
}
public ArticleCommentDto toDto(UserAccountDto userAccountDto) {
return ArticleCommentDto.of(
articleId,
userAccountDto,
content
);
}
}
Request객체입니다. 클라이언트에서 넘겨올때 받을 객체입니다. 정적메서드 of는 게시글의 id인 articleId와 댓글 내용 content만 받아서 리턴하고 있습니다.
toDto는 뷰에서 값을 받아서 dto로 변환해주는 로직입니다.
ArticleCommentService
public void saveArticleComment(ArticleCommentDto dto) {
try {
Article article = articleRepository.getReferenceById(dto.getArticleId());
UserAccount userAccount = userAccountRepository.getReferenceById(dto.getUserAccountDto().getUserId());
articleCommentRepository.save(dto.toEntity(article, userAccount));
} catch (EntityNotFoundException e) {
log.warn("댓글 저장 실패. 댓글 작성에 필요한 정보를 찾을 수 없습니다. - {}", e.getLocalizedMessage());
}
}
컨트롤러에서 호출할 서비스메소드 입니다.
articleCommentRequest DTO에서 toDto를 넘겨 받아 repository에서 getReferenceByid로 article을 가져옵니다. 그후 UserAccount도 같은 방식으로 가져온후 댓글을 세이브 합니다.
여기서 getReferenceById에 대해서는 여기에 정리해둔 글이 있습니다.
ArticleCommentControllerTest
@DisplayName("View 컨트롤러 - 댓글")
@Import({SecurityConfig.class, FormDataEncoder.class})
@WebMvcTest(ArticleCommentController.class)
class ArticleCommentControllerTest {
private final MockMvc mvc;
private final FormDataEncoder formDataEncoder;
@MockBean private ArticleCommentService articleCommentService;
public ArticleCommentControllerTest(@Autowired MockMvc mvc, @Autowired FormDataEncoder formDataEncoder) {
this.mvc = mvc;
this.formDataEncoder = formDataEncoder;
}
@DisplayName("[view][POST] 댓글 등록 - 정상 호출")
@Test
void givenArticleCommentInfo_whenRequesting_thenSavesNewArticleComment() throws Exception {
// Given
long articleId = 1L;
ArticleCommentRequest request = ArticleCommentRequest.of(articleId, "test comment");
willDoNothing().given(articleCommentService).saveArticleComment(any(ArticleCommentDto.class));
// When & Then
mvc.perform(
post("/comments/new")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(formDataEncoder.encode(request))
.with(csrf())
)
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/articles/" + articleId))
.andExpect(redirectedUrl("/articles/" + articleId));
then(articleCommentService).should().saveArticleComment(any(ArticleCommentDto.class));
}
@DisplayName("[view][GET] 댓글 삭제 - 정상 호출")
@Test
void givenArticleCommentIdToDelete_whenRequesting_thenDeletesArticleComment() throws Exception {
// Given
long articleId = 1L;
long articleCommentId = 1L;
willDoNothing().given(articleCommentService).deleteArticleComment(articleCommentId);
// When & Then
mvc.perform(
post("/comments/" + articleCommentId + "/delete")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(formDataEncoder.encode(Map.of("articleId", articleId)))
.with(csrf())
)
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/articles/" + articleId))
.andExpect(redirectedUrl("/articles/" + articleId));
then(articleCommentService).should().deleteArticleComment(articleCommentId);
}
}
'Project > project-board' 카테고리의 다른 글
[Project] 해시태그 검색 구현 (0) | 2022.07.20 |
---|---|
[Project] 게시판 검색기능 (0) | 2022.07.15 |
[Project] 게시글 페이징 처리 구현, 정렬 및 테스트 (0) | 2022.07.14 |
[Project] 게시글, 댓글 비즈니스 로직, 페이지 구현 (0) | 2022.07.14 |
[Project] DTO 설계 (0) | 2022.07.14 |
댓글