김쥬르에 개발일지
Spring Boot 수정 삭제 본문
이번엔 수정 삭제를 구현해보겠습니다.
삭제부터 해보겠습니다.
BlogService.java 파일을 delete() 메서드를 추가합니다.
메서드는 블로그 글의 ID를 받은 뒤 JPA에서 제공하는 deleteById() 메서드를 이용해
데이터베이스에서 데이터를 삭제합니다.
public void delete(long id) {
blogRepository.deleteById(id);
}
/api/articles/{id} DELETE 요청이 오면 글을 삭제하기 위한
findArticles() 메서드를 BlogApiController에 추가하겠습니다.
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Void> deleteArticle(@PathVariable long id) {
blogService.delete(id);
return ResponseEntity.ok()
.build();
}
/api/articles/{id} DELETE 요청이 오면 {id}에 해당하는 값이
@PathVariable 어노테이션을 통해 들어옵니다.
로직이 모두 완성되었으니 실제로 테스트해보겠습니다. 포스트맨에서
HTTP 메서드 : DELETE
URL : http://localhost:8080/api/articles/1
로 설정한후 send를 누릅니다.

이후 전체 글을 조회하여 삭제가 잘됐는지 확인해봅시다.
HTTP 메서드 : GET
URL : http://localhost:8080/api/articles
요청을 보냅시다.

ID가 1인 글이 삭제된걸 확인되었네요.
이번엔 테스트 코드를 작성해보겠습니다.
Given : 블로그 글을 저장합니다.
When : 저장한 블로그 글의 id값으로 삭제 API를 호출합니다.
Then : 응답 코드가 200 OK이고 , 블로그 글 리스트를 전체 조회해 조회한 배열 크기가 0인지 확인합니다.
@DisplayName("deleteArticle: 블로그 글 삭제에 성공한다.")
@Test
public void deleteArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
final String title = "title";
final String content = "content";
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();
}
테스트를 실행해봅시다.

이제 수정 API를 구현해보겠습니다.
엔티티에 요청받은 내용으로 값을
수정하는 메서드를 하나 작성하겠습니다
Article.java 파일을 열어 다음과 같이 작성합니다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {
---------생략----------
public void update(String title, String content) {
this.title = title;
this.content = content;
}
그 다음 블로그 글 수정 요청을 받을 DTO를 작성해야합니다.
dto 디렉터리에 UpdateArticleRequest.java 파일을 만든후 코드를 작성하세요.
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class UpdateArticleRequest {
private String title;
private String content;
}
글에서 수정해야 하는 내용은 제목과 내용이므로
그에 맞게 제목과 내용 필드로 구성했습니다.
다음 BlogService.java 파일을 열어 리포지터리를
사용해 글을 수정하는 update() 메서드를 추가하겠습니다.
@RequiredArgsConstructor // final이 붙거나 @NotNull이 붙은 필드의 생성자 추가
@Service // 빈으로 등록
public class BlogService {
---------생략------------
@Transactional // 트랜잭션 메서드
public Article update(long id, UpdateArticleRequest request) {
Article article = blogRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("not found : " + id));
article.update(request.getTitle(), request.getContent());
return article;
}
}
@Transactional
매칭한 메서드를 하나의 트랜잭션으로 묶는 역할을 합니다
트랜잭션?
데이터베이스의 데이터를 바꾸기 위해 묶은 작업의 단위
이해를 위해 예를 한번 들어보겠습니다.
계좌 이체를 할 때 이런 과정을 거친다고 가정해봅시다.
1. A 계좌에서 출금
2. B 계좌에 입금
그런데 A 계좌에선 출금을 성공하고 B 계좌에선 입금을 진행하는 도중
실패하면 어떻게 될까요? 고객에 입장에서는 출금은 됐는데 입금이 안 된 심각한 상황이 벌어집니다.
이런 상황이 발생하지 않으려면 출금과 입금을 하나의 작업단위로 묶어서
한 단위로 실행하면됩니다. 만약 중간에 실패한다면 트랜잭션의 처음 상태로 모두 되롤리는것이죠
이제 update() 메서드는 엔티티의 필드 값이 바뀌면 중간에
에러가 발생해도 제대로 된 수정을 보장하게 됩니다.
위 코드를 해석해보겠습니다.
Article update(long id, UpdateArticleRequest request)
글의 id 와 업데이트 할 내용을 담은
UpdateArticleRequest 를 받아들이고 업데이트된 글이 반환됩니다.
Article article = blogRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("not found : " + id));
주어진 id 에 해당하는 글을 blogReposutory 를 통해 찾습니다.
만약 글이 존재하지 않으면 orElseThrow 메서드가 호출되어 IllegalArgumentException
발생하며 메시지로 not found : id 를 오류에 포함합니다.
article.update(request.getTitle(), request.getContent());
찾아낸 글에 대해 update 메서드를 호출하여 주어진 request 객체의 제목과 내용을 글의 업데이트합니다.
BlogApiController.java 파일을 열어 코드를 추가하겠습니다.
@RequiredArgsConstructor
@RestController // HTTP Response Body에 객체 데이터를 JSON 형식으로 반환하는 컨트롤러
public class BlogApiController {
private final BlogService blogService;
---------생략------------
@PutMapping("/api/articles/{id}")
public ResponseEntity<Article> updateArticle(@PathVariable long id, @RequestBody UpdateArticleRequest request) {
Article updatedArticle = blogService.update(id, request);
return ResponseEntity.ok()
.body(updatedArticle);
}
}
/api/articles/{id} PUT 요청이 오면 Request Body 정보가 request로 넘어옵니다.
그리고 다시 서비스 클래스의 update() 메서드에 {id}와 request를 넘겨줍니다.
응답값은 body에 담아 전송해줍니다.
이제 실행 테스트를 통해 작동이 잘되는지 확인해보겠습니다.
서버를 실행한후 포스트맨에서
HTTP 메서드 : PUT
URL : http://localhost:8080/api/articles/1
수정내용을 입력해야하는데 Body 탭을 누른후
{"title" : "새블로그" , "content" : "새로운 글 작성"}
작성해준후 send를 눌러 요청을 날려보냅니다.

수정이 됐는지 GET 요청을 통해
확인해봅시다

수정이 잘되었는지도 확인을 해봤습니다.
테스트 코드도 작성해보죠
Given : 블로그 글을 저장하고 , 블로그 글 수정에 필요한 요청 객체를 만듭니다.
When : UPDATE API로 수정 요청을 보냅니다. 이때 요청 타입은 JSON이며
GIVEN절에서 미리 만들어둔 객체를 요청 본문으로 함께 보냅니다.
@DisplayName("updateArticle: 블로그 글 수정에 성공한다.")
@Test
public void updateArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
final String title = "title";
final String content = "content";
Article savedArticle = blogRepository.save(Article.builder()
.title(title)
.content(content)
.build());
final String newTitle = "new title";
final String newContent = "new content";
UpdateArticleRequest request = new UpdateArticleRequest(newTitle, newContent);
// when
ResultActions result = mockMvc.perform(put(url, savedArticle.getId())
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request)));
// then
result.andExpect(status().isOk());
Article article = blogRepository.findById(savedArticle.getId()).get();
assertThat(article.getTitle()).isEqualTo(newTitle);
assertThat(article.getContent()).isEqualTo(newContent);
}
테스트가 잘되는지 확인해봅시다.

CRUD는 모든 기능의 기반이 되는 기능이므로
앞선 내용들을 숙지하고 이해하는건 기본입니다.
다음 포스팅엔 화면 구성을 통해 템플릿 엔진을
알아보고 더 직관적으로 값들에 변화를 봐보도록하겠습니다.
'Spring boot' 카테고리의 다른 글
| Spring Boot 각종 뷰 (1) | 2023.12.31 |
|---|---|
| Spring Boot 화면구성 (1) | 2023.12.29 |
| Spring Boot 블로그 글 조회 (0) | 2023.12.28 |
| Spring Boot 블로그 글 추가하기 (1) | 2023.12.27 |
| Spring Boot REST API (2) | 2023.12.26 |