- 게시글을 수정 및 삭제하는 방법에 대해 알아 볼 것이다.
- 게시글 수정
- PostEdit.java
@Getter
@Setter
@ToString
public class PostEdit {
@NotBlank(message = "title을 입력해주세요")
private String title;
@NotBlank(message = "content를 입력해주세요")
private String content;
@Builder
public PostEdit(String title, String content) {
this.title = title;
this.content = content;
}
}
- PostService.java
@Transactional
public void edit(Long id, PostEdit postEdit) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 글 입니다."));
// post.change(postEdit.getTitle(), postEdit.getContent());
PostEditor.PostEditorBuilder editorBuilder = post.toEditor();
PostEditor postEditor = editorBuilder.title(postEdit.getTitle())
.content(postEdit.getContent())
.build();
post.edit(postEditor);
- @Transactional 어노테이션을 사용하면 해당 메서드의 데이터의 일관성을 유지하기 위해 save() 메서드를 별도로 작성하지 않아도 스프링에서 DB에 저장을 한다. 만약 문제가 생기면 rollback을 한다.
- DB에서 id값을 통해 엔티티를 찾아올 때 null이 반환 될 수 있기 때문에 Optional로 반환하는 것이 맞지만, 해당 엔티티(Post)로 반환하기 위해 엔티티가 아닌 다른 값이 들어오게 될 경우 예외로 처리하여 던져버린다.
1. 엔티티 수정
- 엔티티의 값을 수정하는 가장 기본적인 방법은 변경할 값을 받을 클래스(postEdit)를 생성하여 해당 값을 받아 기존의 값(Post)에 변경하는 메서드(change())를 생성하여 넣는 방법이 있다.
- 위 방법의 경우 가장 기본적인 방법이지만 위와 같이 파라미터의 수가 적을 경우 괜찮지만 파라미터가 엄청나게 늘어나게 되면, 파라미터 순서에 의해서 원하는 값이 원하는 필드에 들어가지 않는 일이 발생할 수 있기 때문에 대비를 해야한다.
- Post.java
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Lob // Java에서는 String이지만 DB에 저장될 때는 Long text로 저장되게 하기 위한 어노테이션이다.
private String content;
@Builder
public Post(String title, String content) {
this.title = title;
this.content = content;
}
// public void change(String title, String content) {
// this.title = title;
// this.content = content;
// }
//위의 경우 파라미터 순서가 변경되면 버그를 찾기 매우 힘들다. 이를 대비해 아래와 같이 사용한다.
public PostEditor.PostEditorBuilder toEditor() {
return PostEditor.builder()
.title(title)
.content(content);
}
// Builder를 넘기는 이유는 build()를 쓰게되면 객체를 생성하며 데이터를 확정시키기 때문이다.
// 데이터를 확정 시키지 않고 넘기기 위해 Builder 형태로 전달한다.
public void edit(PostEditor postEditor) {
title = postEditor.getTitle();
content = postEditor.getContent();
}
}
- PostEditor.java
@Getter
public class PostEditor {
private final String title;
private final String content;
@Builder
public PostEditor(String title, String content) {
this.title = title;
this.content = content;
}
public static PostEditorBuilder builder() {
return new PostEditorBuilder();
}
public static class PostEditorBuilder {
private String title;
private String content;
PostEditorBuilder() {
}
public PostEditorBuilder title(final String title) {
if (title != null) {
this.title = title;
}
return this;
}
public PostEditorBuilder content(final String content) {
if (content != null) {
this.content = content;
}
return this;
}
public PostEditor build() {
return new PostEditor(this.title, this.content);
}
public String toString() {
return "PostEditor.PostEditorBuilder(title=" + this.title + ", content=" + this.content + ")";
}
}
}
2. 수정 엔티티 생성
- 수정용 엔티티를 생성하여 수정용 엔티티에 값을 넣고 해당 값을 실제 엔티티에 넣어 수정하는 방식이다.
- Post.java의 코드에서 아래의 toEditor()메서드를 호출하게 되면 PostEditor 엔티티의 Builder 패턴을 반환한다.
public PostEditor.PostEditorBuilder toEditor() {
return PostEditor.builder()
.title(title)
.content(content);
}
- build()를 하게 되면 builder 패턴을 통해 객체를 생성하지만 build()메서드를 호출하지 않고, [엔티티명]Builer를 통해 데이터를 확정짓지 않고 builder 패턴을 반환할 수 있다.
- 추가로 @Builder 어노테이션이 붙은 생성자의 경우 build() 메서드가 호출되는 시점에 해당 생성자 파라미터에 builder클래스에 담겨있던 값이 넘어간다.
- PostSerivce.java의 코드에선 아래와 같이 toEditor()메서드를 호출하여, Controller에서 넘어온 postEdit 객체에 담긴 데이터를 builder 패턴을 통해 PostEditor 엔티티에 저장한다. 즉, 수정하기 위한 값을 받아 수정 엔티티에 담는다.
PostEditor.PostEditorBuilder editorBuilder = post.toEditor();
PostEditor postEditor = editorBuilder.title(postEdit.getTitle())
.content(postEdit.getContent())
.build();
- Post.java 코드에 edit(PostEditor postEditor)메서드를 받아옴으로서 이전에 여러가지 파라미터를 받아오는 대신 PostEditor 객체 하나만 파라미터로 받아올 수 있기 때문에 가독성 측면에서 좋고, 또 다른 개발자가 볼 때 어떤 값이 수정 가능한 값이지 쉽게 확인할 수 있는 장점이 있다.
public void edit(PostEditor postEditor) {
title = postEditor.getTitle();
content = postEditor.getContent();
}
}
- PostService.java 코드에 edit() 메서드를 추가함으로서 수정 controller가 실행되었을 때 수정 엔티티에 해당하는 PostEditor에 개발자가 의도한 필드의 값들이 주입되고 @Transactional 어노테이션에 의해 변경된 Post 엔티티가 DB에 저장(수정) 된다.
post.edit(postEditor);
- controller에서 service에 수정을 요청하게 되면 그에 해당하는 Service의 edit()메서드가 호출되고 그 안에 post.edit()이 실행되어 수정 코드가 실행된다.
- PostEditor.java
.....
public static PostEditorBuilder builder() {
return new PostEditorBuilder();
}
public static class PostEditorBuilder {
private String title;
private String content;
PostEditorBuilder() {
}
public PostEditorBuilder title(final String title) {
if (title != null) {
this.title = title;
}
return this;
}
public PostEditorBuilder content(final String content) {
if (content != null) {
this.content = content;
}
return this;
}
public PostEditor build() {
return new PostEditor(this.title, this.content);
}
public String toString() {
return "PostEditor.PostEditorBuilder(title=" + this.title + ", content=" + this.content + ")";
}
}
- PostEditor코드를 보게되면 builder 클래스의 코드를 사용하는 것을 확인 할 수 있다.
- 기존의 builder 클래스의 코드를 그대로 가져와서
.....
public PostEditorBuilder title(final String title) {
if (title != null) {
this.title = title;
}
return this;
}
public PostEditorBuilder content(final String content) {
if (content != null) {
this.content = content;
}
return this;
}
.....
- 위 코드에서 if문을 추가함으로서 build 클래스를 사용할 때 기존에 값이 있었다면 해당 값을 그대로 사용하기 위해 코드를 변경하였다.
- controller에서 수정 Service가 호출되면 아래의 post 클래스의 toEditor() 메서드 및 builder 패턴을 통해 postEdit의 값들을 넣어 새로운 PostEditor 객체를 생성한다.
.....
PostEditor.PostEditorBuilder editorBuilder = post.toEditor();
PostEditor postEditor = editorBuilder.title(postEdit.getTitle())
.content(postEdit.getContent())
.build();
.....
- 최종적으로 Service의 post.edti() 메서드가 호출되고
.....
post.edit(postEditor);
.....
- 아래와 같이 edit() 메서드를 통해 넘어온 postEditor 객체의 값들이 post 객체에 주입된다.
.....
public void edit(PostEditor postEditor) {
title = postEditor.getTitle();
content = postEditor.getContent();
}
.....
- 마지막으로 값이 변경된 Post 엔티티는 @Transactional 어노테이션에 의해 자동으로 변경된 부분이 DB에 저장되게 된다.
- 게시글 삭제
- 게시글 삭제의 경우 JPA 기본적으로 생성되어 있는 delete() 메서드를 통해 삭제 메서드를 실행한다.
- PostServiceTest.java
@Test
@DisplayName("게시글 삭제")
void test6() {
// given
Post post = Post.builder()
.title("BIS")
.content("상도더샵")
.build();
postRepository.save(post);
// when
postService.delete(post.getId());
// then
Assertions.assertEquals(0, postRepository.count());
}
}
- PostService.java
.....
public void delete(Long id) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 글 입니다."));
// -> 존재하는 경우
postRepository.delete(post);
}
}
'Programming > Spring' 카테고리의 다른 글
Spring - 예외 처리 (0) | 2023.09.06 |
---|---|
Spring, Java - Builder 패턴 분석 (0) | 2023.09.06 |
Spring - 페이징 (Jpa, Querydsl) (0) | 2023.08.31 |
Spring - 게시글 조회 (다건 조회, 임시 H2 활용한 실제 서비스 확인) (0) | 2023.08.30 |
Spring - 게시글 조회, 클래스 분리 (단건) (0) | 2023.08.29 |