게시글 수정

이제 CRUD 의 R 까지 했으니 이젠 U 차례다.

게시글 수정은 JPA 의 변경감지를 이용해서 구현해보자.

 

PostController

데이터를 서비스로 넘겨준 후 수정된 Post 데이터를 반환한다.

@PatchMapping("/posts/{postId}")
public PostResponse edit(@PathVariable Long postId, @RequestBody @Valid PostEdit request) {
    return postService.edit(postId, request);
}

ㄴ @PathVariable

URL 쿼리 파라미터로 Post 의 id 값을 받는다.

ㄴ @RequestBody 

JSON 요청으로 PostEdit 객체에 데이터를 담는다

 

PostEdit

PostCreate 와 거의 같으니까 이걸로 퉁치면 안되나? 라고 생각할 수 있지만 그러다간 큰일날수있다.

기능이 다르면 구조가 비슷해도 명확하게 분리하는걸 절대적으로 추천한다.

지금은 비슷할지라도 나중엔 완전히 달라질 수가 있으니 그때 가서 고치려고 하면 굉장히 골아프다.

@Getter
@NoArgsConstructor
public class PostEdit {

    @NotBlank(message = "제목을 입력해주세요.")
    private String title;

    @NotBlank(message = "내용을 입력해주세요.")
    private String content;

    @Builder
    public PostEdit(String title, String content) {
        this.title = title;
        this.content = content;
    }
}

 

PostService

컨트롤러로 부터 받은 데이터로 수정을 진행하고 컨트롤러로 수정된 Post 데이터를 반환한다.

@Transactional
public PostResponse edit(Long id, PostEdit request) {
    Post post = postRepository.findById(id)
        .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 글입니다."));

    post.edit(request.getTitle(), request.getContent());
    return new PostResponse(post);
}

ㄴ @Transactional

트랜잭션을 적용한다는 애노테이션이다.

JPA 의 변경감지를 이용하면 별도의 리포지토리 저장 메서드 호출없이 트랜잭션만 걸어줘도

트랜잭션이 끝날 때 자동으로 엔티티의 변경 값이 업데이트 된다.

 

Post

Post 엔티티 내에 수정 메서드를 내장해 캡슐화한다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @Lob
    private String content;

    @Builder
    public Post(String title, String content) {
        this.title = title;
        this.content = content;
    }

    public void edit(String title, String content) {
        this.title = title;
        this.content = content;
    }
}

 


PostServiceTest

글 내용은 그대로 두고 제목만 변경 시 기대한대로 동작하는지 확인하는 테스트를 작성한다.

@DisplayName("글 제목 수정")
@Test
void edit() {
    // given
    Post post = Post.builder()
        .title("우리 이쁜 미카공주님")
        .content("우리 공주님")
        .build();
    postRepository.save(post);

    PostEdit request = PostEdit.builder()
        .title("사랑스러운 공주님")
        .content("우리 공주님")  // 이 부분은 client 와의 상의가 필요
        .build();

    // when
    postService.edit(post.getId(), request);
    Post changedPost = postRepository.findById(post.getId())
        .orElseThrow(() -> new RuntimeException("글이 존재하지 않습니다. id = " + post.getId()));

    // then
    assertEquals(1L, postRepository.count());
    assertEquals("사랑스러운 공주님", changedPost.getTitle());
    assertEquals("우리 공주님", changedPost.getContent());
}

 

테스트 수행 시 우리가 원했던 대로 동작하며 테스트가 성공함을 알 수 있다.

 


PostControllerTest

글 내용은 그대로 두고 제목만 변경 시 기대한대로 동작하는지 확인하는 테스트를 작성한다.

@DisplayName("글 제목 수정")
@Test
void edit() throws Exception {
    // given
    Post post = Post.builder()
        .title("우리 이쁜 미카공주님")
        .content("우리 공주님")
        .build();
    postRepository.save(post);

    PostEdit request = PostEdit.builder()
        .title("사랑스러운 공주님")
        .content("우리 공주님")
        .build();

    // expected
    mockMvc.perform(
            MockMvcRequestBuilders.patch("/posts/{postId}", post.getId())
                .contentType(APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(request))
        )
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.title").value("사랑스러운 공주님"))
        .andExpect(jsonPath("$.content").value("우리 공주님"))
        .andDo(print());
}

 

테스트 수행 시 우리가 원했던 대로 동작하며 테스트가 성공함을 알 수 있다.

 


고민해볼점

이 글에서 작성한 방식은 수정할 필드 외의 데이터를 보내지 않을 시 나머지 부분은 null 이 될 수 있다.

수정 시 Client 측에서 서버로 데이터를 어떻게 보내냐에 따라 수정 메서드를 고쳐야할 필요가 있다.

  • 수정할 필드 데이터만 보내냐
  • 수정할 필드 및 그대로인 필드 데이터 다 보내냐

 

+ Recent posts