@RequiredArgsConstructor // final이 붙거나 @NotNull이 붙은 필드의 생성자 추가
@Service // 빈으로 등록
public class BlogService {
private final BlogRepository blogRepository;
// 블로그 글 조회 메서드
public List<Article> findAll() {
return blogRepository.findAll();
}
}
api/articles GET
요청이 오면 글 목록을 조회할findAllArticles()
응답을 위한 DTO 작성
dto
디렉터리에ArticleResponse.java
파일 생성 후 코드 작성
@Getter
public class ArticleResponse {
private final String title;
private final String content;
public ArticleResponse(Article article) {
this.title = article.getTitle();
this.content = article.getContent();
}
}
api/articles Get
요청이 들어오면 글 전체를 도회하는blogService.findAll()
메서드를 호출한 다음 응답용 객체ArticleResponse
로 파싱해body
에 담아 클라이언트에게 응답합니다.해당 코드는 스트림을 적용하였습니다.
@RequiredArgsConstructor
@RestController // HTTP Response Body에 객체 데이터를 JSON 형식으로 반환하는 컨트롤러
public class BlogApiController {
private final BlogService blogService;
@GetMapping("/api/articles")
public ResponseEntity<List<ArticleResponse>> findAllArticles() {
List<ArticleResponse> articles = blogService.findAll()
.stream()
.map(ArticleResponse::new)
.toList();
return ResponseEntity.ok()
.body(articles);
}
]
글 목록 조회를 위해 더미 값을 미리 Database에 넣어보겠습니다.
resources
패키지 안에data.sql
파일을 생성한 다음INSERT INTO article (title, content) VALUES ('제목1', '내용1') INSERT INTO article (title, content) VALUES ('제목2', '내용2') INSERT INTO article (title, content) VALUES ('제목3', '내용3')
를 넣어주고 실행하시면 Postman으로 GET 요청을 보낼 때 해당 값들이 조회됩니다.
포스트맨으로 이번엔
HTTP 메서드 → GET
으로 변경
http://localhost:8080/api/articles
를 입력한 다음Send
를 보내면
data.sql
에서 Database에 넣어준 값들이 잘 보입니다 !
앞어 작성한 포스트의 글 작성 테스트 코드인
BlogApiControllerTest.java
에 이어서 작성하겠습니다 !
@DisplayName("글 전체 게시글 조회 성공")
@Test
public void findAllArticles() throws Exception {
// given
final String url = "/api/articles";
final String title = "title_example";
final String content = "content_example";
blogRepository.save(Article.builder()
.title(title)
.content(content)
.build());
// when
final ResultActions resultActions = mockMvc.perform(get(url)
.accept(MediaType.APPLICATION_JSON));
// then
resultActions
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].content").value(content))
.andExpect(jsonPath("$[0].title").value(title));
}
기존의 코드에서 아래 코드를 추가합니다.
public Article findById(long id) {
return blogRepository.findById(id) // 엔티티를 조회하고, 없으면 예외 발생
.orElseThrow(() -> new IllegalArgumentException("not found: " + id));
}
기존의 코드에서 아래 코드를 추가합니다.
@GetMapping("api/articles/{id}")
public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id) {
Article article = blogService.findById(id);
return ResponseEntity.ok()
.body(new ArticleResponse(article));
}
@PathVariable
애너테이션은 URL에서 값을 가져오는 애너테이션으로/api/articles/1
GET
요청을 받으면id
에 1이라는 값이 저장됩니다.해당 1의 id 값은 서비스 클래스의
findBtId()
메서드로 전달되어 1번 블로그 글을 조회하게 됩니다.
@DisplayName("단일 글 조회 성공")
@Test
public void findArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
final String title = "title_example";
final String content = "content_example";
Article savedArticle = blogRepository.save(Article.builder()
.title(title)
.content(content)
.build());
// when
final ResultActions resultActions = mockMvc.perform(get(url, savedArticle.getId()));
// then
resultActions
.andExpect(status().isOk())
.andExpect(jsonPath("$.content").value(content))
.andExpect(jsonPath("$.title").value(title));
}
기존의 코드에 아래 코드를 추가합니다.
public void delete(long id) {
blogRepository.deleteById(id);
}
기존의 코드에 아래 코드를 추가합니다.
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Void> deleteArticle(@PathVariable long id) {
blogService.delete(id);
return ResponseEntity.ok().build();
}
DELETE
요청을 아래와 같이 보내면글을 전체 조회할 때 1번 글이 삭제된 것을 확인할 수 있다.
@DisplayName("글 삭제 성공")
@Test
public void deleteArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
final String title = "title_example";
final String content = "content_example";
Article savedArticle = blogRepository.save(Article.builder()
.title(title)
.content(content)
.build());
// when
mockMvc.perform(delete(url, savedArticle.getId()))
.andExpect(status().isOk());
// then
List<Article> articles = blogRepository.findAll();
assertThat(articles).isEmpty();