#16 board : article controller impl
This commit is contained in:
@@ -1,27 +1,43 @@
|
||||
package com.example.board.controller;
|
||||
|
||||
import com.example.board.domain.type.SearchType;
|
||||
import com.example.board.dto.response.ArticleResponse;
|
||||
import com.example.board.dto.response.ArticleWithCommentsResponse;
|
||||
import com.example.board.service.ArticleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/articles")
|
||||
@Controller
|
||||
public class ArticleController {
|
||||
|
||||
private final ArticleService articleService;
|
||||
|
||||
@GetMapping
|
||||
public String articles(ModelMap map) {
|
||||
map.addAttribute("articles", List.of());
|
||||
public String articles(
|
||||
@RequestParam(required = false) SearchType searchType,
|
||||
@RequestParam(required = false) String searchValue,
|
||||
@PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
|
||||
ModelMap map) {
|
||||
map.addAttribute("articles", articleService.searchArticles(searchType, searchValue, pageable).map(ArticleResponse::from));
|
||||
|
||||
return "articles/index";
|
||||
}
|
||||
|
||||
@GetMapping("/{articleId}")
|
||||
public String article(@PathVariable Long articleId, ModelMap map) {
|
||||
map.addAttribute("article", "article");
|
||||
map.addAttribute("articleComments", List.of());
|
||||
ArticleWithCommentsResponse article = ArticleWithCommentsResponse.from(articleService.getArticle(articleId));
|
||||
map.addAttribute("article", article);
|
||||
map.addAttribute("articleComments", article.articleCommentsResponse());
|
||||
return "articles/detail";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public record ArticleWithCommentResponse(
|
||||
public record ArticleWithCommentsResponse(
|
||||
Long id,
|
||||
String title,
|
||||
String content,
|
||||
@@ -16,20 +16,20 @@ public record ArticleWithCommentResponse(
|
||||
LocalDateTime createdAt,
|
||||
String email,
|
||||
String nickname,
|
||||
Set<ArticleCommentResponse> articleCommentResponses
|
||||
Set<ArticleCommentResponse> articleCommentsResponse
|
||||
) implements Serializable {
|
||||
|
||||
public static ArticleWithCommentResponse of(Long id, String title, String content, String hashtag, LocalDateTime createdAt, String email, String nickname, Set<ArticleCommentResponse> articleCommentResponses) {
|
||||
return new ArticleWithCommentResponse(id, title, content, hashtag, createdAt, email, nickname, articleCommentResponses);
|
||||
public static ArticleWithCommentsResponse of(Long id, String title, String content, String hashtag, LocalDateTime createdAt, String email, String nickname, Set<ArticleCommentResponse> articleCommentResponses) {
|
||||
return new ArticleWithCommentsResponse(id, title, content, hashtag, createdAt, email, nickname, articleCommentResponses);
|
||||
}
|
||||
|
||||
public static ArticleWithCommentResponse from(ArticleWithCommentsDto dto) {
|
||||
public static ArticleWithCommentsResponse from(ArticleWithCommentsDto dto) {
|
||||
String nickname = dto.userAccountDto().nickname();
|
||||
if (nickname == null || nickname.isBlank()) {
|
||||
nickname = dto.userAccountDto().userId();
|
||||
}
|
||||
|
||||
return new ArticleWithCommentResponse(
|
||||
return new ArticleWithCommentsResponse(
|
||||
dto.id(),
|
||||
dto.title(),
|
||||
dto.content(),
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
package com.example.board.controller;
|
||||
|
||||
import com.example.board.config.SecurityConfig;
|
||||
import com.example.board.dto.ArticleWithCommentsDto;
|
||||
import com.example.board.dto.UserAccountDto;
|
||||
import com.example.board.service.ArticleService;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@@ -20,6 +30,9 @@ class ArticleControllerTest {
|
||||
|
||||
private final MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private ArticleService articleService;
|
||||
|
||||
public ArticleControllerTest(@Autowired MockMvc mockMvc) {
|
||||
this.mockMvc = mockMvc;
|
||||
}
|
||||
@@ -28,6 +41,8 @@ class ArticleControllerTest {
|
||||
@Test
|
||||
public void givenNothing_whenRequestingArticlesView_thenReturnsArticlesView() throws Exception {
|
||||
// given
|
||||
given(articleService.searchArticles(eq(null), eq(null), any(Pageable.class)))
|
||||
.willReturn(Page.empty());
|
||||
|
||||
// when & then
|
||||
mockMvc.perform(get("/articles"))
|
||||
@@ -36,21 +51,28 @@ class ArticleControllerTest {
|
||||
.andExpect(view().name("articles/index"))
|
||||
.andExpect(model().attributeExists("articles"))
|
||||
;
|
||||
|
||||
then(articleService).should().searchArticles(eq(null), eq(null), any(Pageable.class));
|
||||
}
|
||||
|
||||
@DisplayName("[view][GET] 게시글 상세 페이지 - 정상 호출")
|
||||
@Test
|
||||
public void givenNothing_whenRequestingArticleView_thenReturnsArticleView() throws Exception {
|
||||
// given
|
||||
Long articleId = 1L;
|
||||
|
||||
given(articleService.getArticle(articleId)).willReturn(createArticleWithCommentDto());
|
||||
|
||||
// when & then
|
||||
mockMvc.perform(get("/articles/1"))
|
||||
mockMvc.perform(get("/articles/" + articleId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
|
||||
.andExpect(view().name("articles/detail"))
|
||||
.andExpect(model().attributeExists("article"))
|
||||
.andExpect(model().attributeExists("articleComments"))
|
||||
;
|
||||
|
||||
then(articleService).should().getArticle(articleId);
|
||||
}
|
||||
|
||||
@Disabled("구현 중")
|
||||
@@ -80,4 +102,34 @@ class ArticleControllerTest {
|
||||
.andExpect(view().name("articles/search-hashtag"))
|
||||
;
|
||||
}
|
||||
|
||||
private ArticleWithCommentsDto createArticleWithCommentDto() {
|
||||
return ArticleWithCommentsDto.of(
|
||||
1L,
|
||||
createUserAccountDto(),
|
||||
Set.of(),
|
||||
"title",
|
||||
"content",
|
||||
"#java",
|
||||
LocalDateTime.now(),
|
||||
"bobby",
|
||||
LocalDateTime.now(),
|
||||
"bobby"
|
||||
);
|
||||
}
|
||||
|
||||
private UserAccountDto createUserAccountDto() {
|
||||
return UserAccountDto.of(
|
||||
1L,
|
||||
"bobby",
|
||||
"1234",
|
||||
"bobby@email.com",
|
||||
"bobby",
|
||||
"memo",
|
||||
LocalDateTime.now(),
|
||||
"bobby",
|
||||
LocalDateTime.now(),
|
||||
"bobby"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user