지난번에 포스팅한 Create에 이어서 게시판을 조회하는 WAS 단 로직을 포스팅하려 합니다. 게시판 조회는 단건 조회와 전체 조회로 나뉩니다. 물론 검색 기능도 조회에 해당하지만, 검색 기능은 추후에 포스팅하겠습니다. Gradle 빌드나 프로젝트 구조는 깃허브 Bincolog를 참고해주세요!
Response 생성📗
처음에는 PostResponse 클래스를 생성합니다. 저번에 언급했던 Entity와 Request, Response는 분류해야 하기 때문입니다. 못 보신 분들은 아래 사진을 참고해주세요😄
Response 클래스는 서비스 정책에 맞게 구현해야 합니다. 클라이언트에서 어떠한 결과 값을 원하는지에 대해서는 항상 다르기 때문입니다. 저는 게시글을 조회했을 때 해당 게시글의 id값, 제목, 내용을 가져오도록 하였습니다.
@Getter
public class PostResponse {
private final Long id;
private final String title;
private final String content;
// 생성자 오버로딩
public PostResponse(Post post){
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
}
@Builder
public PostResponse(Long id, String title, String content) {
this.id = id;
this.title = title.substring(0, Math.min(title.length(), 10));
this.content = content;
}
}
@Getter 어노테이션과 @Builder 어노테이션은 지난 포스팅에서 설명하였으므로 따로 설명은 생략하겠습니다. 지난 번 게시판 작성 로직을 구현했을 때, PostCreate 클래스에서는 final로 선언하지 않았었는데요. 이번 Response 클래스에는 final로 값들을 선언하였습니다.
Java에서는 final을 선언함으로 인해 상수라는 개념을 가지게 됩니다. 상수라는 것은 절대 변하지 않는 값을 뜻하고, 쉽게 말하면 ReadOnly 속성을 가지게 되는 것입니다.
📌게시글을 조회하는 로직을 탔을 때, 조회를 한 후 그 값이 어떠한 상황에도 변하면 안되기 때문에 final로 선언하였습니다.
또한, 제목의 길이가 길 때 제목의 최대 길이를 10글자로 끊어주는 방식을 substring 메서드와 Math.min 메서드를 사용하여 구현하였습니다. (필수 사항은 아닙니다.)
Controller 생성📙
단건 조회 메서드의 Controller 로직은 간단하게 구현 됩니다. GetMapping으로 단건 조회하고 싶은 게시글의 Id값을 받아서 Service 클래스로 넘겨주기만 하면 됩니다.
@GetMapping("/posts/{postId}")
public PostResponse get(@PathVariable Long postId){
return postService.get(postId);
}
게시글을 작성하였을 때, PostMapping으로 Json 형식의 데이터를 보낸다면 @RequestBody 어노테이션을 통해 값을 넘겨 받지만, GetMapping으로 url을 통해 넘어오는 데이터는 @PathVariable 어노테이션으로 값을 넘겨 받습니다.
Service 생성📒
public PostResponse get(Long id){
Post post = postRepository.findById(id)
.orElseThrow(IllegalArgumentException::new);
return PostResponse.builder()
.id(post.getId())
.title(post.getTitle())
.content(post.getContent())
.build();
}
Service 클래스에서는 Controller에서 넘겨준 id 값을 파라미터 값으로 받습니다. 그리고 JpaRepository에서 기본적으로 제공하는 findById() 메서드를 이용하여 원하는 게시글을 찾게 됩니다.
여기서 orElseThrow는 넘겨받은 Id값에 해당하는 게시글이 없을 때 예외처리를 해주는 것입니다. 추후에는 따로 예외처리 클래스를 만들어서 커스터마이징을 할 예정입니다.
DB에서 Entity인 Post 클래스로 게시글을 찾아오고, 아까 만든 Response객체에 Builder 패턴을 이용하여 값을 담아주고 바로 리턴해줍니다.
Controller Test 생성📘
objectMapper, mockMvc, postRepository의 빈 주입 및 @BeforeEach를 통해 서로 다른 테스트에 영향을 끼치지 않도록 DB안에 값을 삭제해주는 메서드를 지난번에 구현했었습니다.
@Autowired
private ObjectMapper objectMapper;
@Autowired
private MockMvc mockMvc;
@Autowired
private PostRepository postRepository;
@BeforeEach
void clean() {
postRepository.deleteAll();
}
그럼 바로 테스트 코드를 짜 볼까요?
@Test
@DisplayName("글 한개 조회")
void test4() throws Exception{
// given
Post post = Post.builder()
.title("foo123412341234")
.content("bar")
.build();
postRepository.save(post);
// expected
mockMvc.perform(MockMvcRequestBuilders.get("/posts/{postId}",post.getId())
.contentType(APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(post.getId()))
.andExpect(jsonPath("$.title").value("foo1234123"))
.andExpect(jsonPath("$.content").value("bar"))
.andDo(print());
}
given section
given 단계에서는 원하는 제목과 내용을 Builder 패턴을 이용하여 새로운 게시글을 하나 추가해줍니다. 그리고 JpaRepository에서 기본적으로 제공해주는 save() 메서드를 이용하여 저장해줍니다.
expected section
expected 단계에서는 mockMvc를 이용하여 컨트롤러에서 작성한 url을 매핑해줍니다. 또한, given 단계에서 저장한 게시글의 Id값을 같이 넘겨줍니다.
그리고 200(status(). isOk()) 코드가 내려오는지부터 id, title, content 값이 일치하는지에 대한 테스트 코드를 작성합니다. 또한, andDo(print()) 메서드를 이용하여 결과값을 로그로 볼 수 있게 작성하였습니다.
근대 andExpect로 테스트 코드를 작성할 때, title의 값은 처음에 "foo123412341234"로 저장하였는데 비교 값은 "foo1234123"으로 작성했을까요?
위에서 만든 PostResponse의 @Builder를 적용한 생성자를 보시면 subString을 이용해서 제목을 10글자로 제한했기 때문입니다.
[ 테스트 결과 ]
Service Test 생성📔
@Test
@DisplayName("글 한개 조회")
void test2() {
//given
Post requestPost = Post.builder()
.title("제목1")
.content("내용1")
.build();
postRepository.save(requestPost);
//when
PostResponse response = postService.get(requestPost.getId());
//then
assertNotNull(response);
assertEquals("제목1",response.getTitle());
assertEquals("내용1",response.getContent());
}
Service 테스트는 Controller 테스트와 많이 유사합니다. given 단계에서는 똑같이 Entity인 Post를 save() 메서드를 이용하여 저장해줍니다
when 단계에서는 아까 위에서 만든 postService의 get() 메서드를 이용하여 given 단계에서 저장한 게시글의 id값을 이용하여 게시글을 조회합니다.
마지막으로 then 단계에서는 처음으로 assertNotNull을 이용하여 게시글이 존재하는지 체크 후에, 조회한 게시글의 제목과 내용을 비교해 줍니다.
[ 테스트 결과 ]
👨👩👦👦 오픈채팅방 운영
취업을 준비하는 예비 개발자분들을 위한 질문&답변할 수 있는 공간을 만들었습니다. 취업과 이직을 하기 위해서 어떤 걸 중점적으로 준비해야 하는지부터 포트폴리오&이력서 작성법 등 다양한 질문들을 받고 답변을 드립니다. 참여하셔서 다양한 정보 얻고 가시면 좋을 것 같네요😁
참여코드 : 456456
https://open.kakao.com/o/gVHZP8dg
👨💻 전자책 출간
아울러 제가 🌟비전공자에서 2년만에 보안 전문 중견기업으로 이직 한 방법들을 정리한 전자책을 출간 하게 되었습니다. 어떤 걸 공부해야 하는지, 이직을 위해서 무엇을 준비해야 하는지, 제가 받았던 기술 면접 리스트 등 다양한 목차로 구성되어 있습니다. 또한, 구매 시 1:1 채팅을 이용하여 포트폴리오 첨삭을 도와드리고 있습니다. 🐕전자책으로 얻은 모든 수익은 유기견 센터 '팅*벨 입양센터'에 후원될 예정입니다. 관심 있으신 분들은 아래 링크를 참고해주세요😁
마치며
지금까지 게시글 단건 조회 api를 만들어 보았습니다. 모든 포스팅에 하나하나 자세히 언급하고 싶지만, 지난번에 언급했던 것들도 언급하면 포스팅 내용이 너무 길어져서 생략한 부분이 꽤 많았던 것 같습니다. 따라 하시는 분들은 꼭 게시판 글 작성 api부터 봐주세요!
코드의 결함이나 문제가 있을 시 댓글로 알려주시면 정말 감사하겠습니다 :)
이전 포스팅
* [ SpringBoot JPA 게시판 CRUD(Create) ]
* [ SpringBoot JPA 게시판 CRUD(Create-TDD) ]
다음 포스팅
* [ SpringBoot JPA 게시판 CRUD(Read - 다중 조회/페이징 처리/TDD) ]
* [ SpringBoot JPA 게시판 CRUD(Update-TDD) ]
* [ SpringBoot JPA 게시판 CRUD(Delete-TDD) ]
* [ SpringBoot JPA 게시판 CRUD(예외처리) ]
'JPA' 카테고리의 다른 글
SpringBoot JPA 게시판 CRUD 구현(Delete-TDD) (0) | 2022.07.25 |
---|---|
SpringBoot JPA 게시판 CRUD 구현(Update-게시글 수정) (0) | 2022.07.21 |
SpringBoot JPA 게시판 CRUD 구현(다중 조회/ Paging / TDD) (0) | 2022.07.21 |
SpringBoot JPA 게시판 CRUD 구현(Create - TDD) (0) | 2022.07.18 |
SpringBoot JPA 게시판 CRUD 구현(Create) (0) | 2022.07.18 |