Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fa6a440
docs: 과제 제출을 위한 Test Commit
goodperiodt Apr 1, 2025
4c20844
feat: post 생성 entity, dto 작성 및 controller, service, repository 구현
goodperiodt Apr 1, 2025
a1b9b11
feat: post 생성 entity, dto 작성 및 controller, service, repository 구현
goodperiodt Apr 1, 2025
4a829ea
feat: post 수정 dto 작성 및 controller, service, repository 구현
goodperiodt Apr 1, 2025
6d51206
build.gradle 에 dto 유효성 검사하는 의존성 추가
goodperiodt Apr 1, 2025
2027cc8
feat: 게시글 삭제 dto 생성, controller, service 구현
goodperiodt Apr 1, 2025
516a098
feat: 게시글 조회 dto 생성, controller, service 구현
goodperiodt Apr 1, 2025
22475d7
feat: 댓글 생성 dto 작성, controller, service 구현
goodperiodt Apr 1, 2025
46664e1
rename: DeletePost --> DeletePostResponseDto
goodperiodt Apr 1, 2025
fbc5026
- rename: 클래스명 변경으로 인한 타입 수정
goodperiodt Apr 1, 2025
6e4d821
style: 코드 포맷팅
goodperiodt Apr 1, 2025
0065fe7
feat: 댓글 생성 dto 작성, controller, service 구현
goodperiodt Apr 1, 2025
07186a2
feat: 댓글 삭제 dto 작성, controller, service 구현
goodperiodt Apr 1, 2025
f4611c6
feat: BaseEntity 에 delete() 메서드 작성 --> 자식 엔터티에 상속되므로 Comment, Post 에 …
goodperiodt Apr 1, 2025
a17fbe2
feat: 삭제 시 게시글과 함께 해당 게시글의 모든 댓글도 삭제 처리
goodperiodt Apr 2, 2025
460e37b
feat: ShowPostOneResponseDto 내 필드 조정으로 게시물 조회시 해당 게시물에 작성된 댓글 조회 구현
goodperiodt Apr 2, 2025
c3ccb45
refact: PostController 에서 update() 메서드만 예외 처리
goodperiodt Apr 2, 2025
d2d83b3
docs: 구현시 어렵거나 이해가 안되는 부분 작성
goodperiodt Apr 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### 구현 시 어렵거나 이해가 되지 않는 부분
- 페이지네이션 구현 과정이 이해가 가지 않는다.
- 페이지네이션 구현시 클라이언트로부터 전달받아야할 파라미터의 기준을 모르겠다.
- 그리고 데이터를 전달받아서 서비스 계층에서 어떻게 로직을 구현해야할지 모르겠다.
- 공통필드인 createAt, updateAt 위에 작성되는 어노테이션의 차이와 db 삽입시 생성일시, 업데이트일시가 삽입되는 일련의 과정을 모르겠다.
- @TimeStamp, @CreatedDate, @CreationTimestamp 의 차이와 @TimeStamp 랑 @UpdateTimestamp 의 차이를 모름.
- 컨트롤러단에서 전역 예외처리하는 방법을 검색없이 구현하려니 어렵다.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-validation'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.sparta.board.application.dto.request;

import io.sparta.board.domain.model.Post;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.ToString;

@ToString
@Getter
public class PostCreationRequestDto {
@NotBlank(message = "제목 입력은 필수입니다.")
private String title;
@NotBlank(message = "내용 입력은 필수입니다.")
private String content;

public Post toEntity() {
return Post.builder()
.title(this.title)
.content(this.content)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.sparta.board.application.dto.request;

import io.sparta.board.domain.model.Post;
import lombok.*;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class PostUpdateRequestDto {
private String title;
private String content;

public Post toEntity() {
return Post.builder()
.title(title)
.content(content)
.build();
}

public boolean isNotValid() {
// null, 빈 문자열, 공백으로 채워진 문자열이라면 true 를 반환하는 isBlank()
// title 과 content 둘 다 값이 없다면 true 를 반환한다.
return (this.title == null || this.title.isBlank()) && (this.content == null || this.content.isBlank());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Comment;
import lombok.Getter;
import java.time.LocalDateTime;
import java.util.UUID;

@Getter
public class CommentCreateResponseDto {
private UUID id;
private UUID postId;
private String content;
private LocalDateTime createdAt;

public CommentCreateResponseDto(Comment comment) {
this.id = comment.getId();
this.postId = comment.getPost().getId();
this.content = comment.getContent();
this.createdAt = comment.getCreatedAt();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Comment;
import io.sparta.board.domain.model.Post;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
public class CommentUpdateResponseDto {
private UUID id;
private String content;
private UUID postId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

public CommentUpdateResponseDto(Comment comment) {
this.id = comment.getId();
this.content = comment.getContent();
this.postId = comment.getPost().getId();
this.createdAt = comment.getCreatedAt();
this.updatedAt = comment.getUpdatedAt();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Comment;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
public class DeleteCommentResponseDto {
private UUID id;
private String comment;
private boolean deleted;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private UUID postId;

public DeleteCommentResponseDto(Comment comment) {
this.id = comment.getId();
this.comment = comment.getContent();
this.deleted = comment.isDeleted();
this.createdAt = comment.getCreatedAt();
this.updatedAt = comment.getUpdatedAt();
this.postId = comment.getPost().getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Post;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class DeletePostResponseDto {
private UUID id;
private String title;
private String content;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private boolean deleted;

public DeletePostResponseDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
// boolean 타입의 필드 값을 얻으려면 is 로 얻을 것
this.deleted = post.isDeleted();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Post;
import lombok.*;

import java.time.LocalDateTime;
import java.util.UUID;

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class PostCreationResponseDto {
private UUID id;
private String title;
private String content;
private LocalDateTime createdAt;

public PostCreationResponseDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.createdAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.sparta.board.application.dto.response;


import io.sparta.board.domain.model.Post;
import lombok.*;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class PostUpdateResponseDto {
private UUID id;
private String title;
private String content;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

public PostUpdateResponseDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.createdAt = post.getCreatedAt();
this.updatedAt = post.getUpdatedAt();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.sparta.board.application.dto.response;

import io.sparta.board.domain.model.Comment;
import io.sparta.board.domain.model.Post;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ShowPostOneResponseDto {
private UUID id;
private String title;
private String content;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private boolean deleted;
private List<ShowCommentResponseDto> commentList = new ArrayList<>();

public ShowPostOneResponseDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.createdAt = post.getCreatedAt();
this.updatedAt = post.getUpdatedAt();
this.deleted = post.isDeleted();
// *** this.commentList = post.getComments(); 이렇게 작성했더니 게시글과 댓글이 무한 참조되는 상황이 발생
this.commentList = makeCommentList(post.getComments());
}

private List<ShowCommentResponseDto> makeCommentList(List<Comment> comments) {
for (Comment comment : comments) this.commentList.add(new ShowCommentResponseDto(comment));
return this.commentList;
}

@Getter
@Setter
private static class ShowCommentResponseDto {
private UUID id;
private String content;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private boolean deleted;

private ShowCommentResponseDto(Comment comment) {
this.id = comment.getId();
this.content = comment.getContent();
this.createdAt = comment.getCreatedAt();
this.updatedAt = comment.getUpdatedAt();
this.deleted = comment.isDeleted();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package io.sparta.board.application.service;

import io.sparta.board.application.dto.response.CommentCreateResponseDto;
import io.sparta.board.application.dto.response.CommentUpdateResponseDto;
import io.sparta.board.application.dto.response.DeleteCommentResponseDto;
import io.sparta.board.domain.model.Comment;
import io.sparta.board.domain.model.Post;
import io.sparta.board.domain.repository.CommentRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.crossstore.ChangeSetPersister;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.UUID;

@Service
@RequiredArgsConstructor
@Slf4j
public class CommentService {
private final CommentRepository commentRepository;
private final PostService postService;

public CommentCreateResponseDto create(UUID postId, Map<String, String> request) {
// 1. 게시물 존재 여부 확인
Post post = postService.getPost(postId);

// 2. 클라이언트가 전달한 데이터 여부 확인
// isBlank() 는 빈문자열("")과 공백으로만 채워진 문자열을 검증하는 역할, isEmpty() 는 공백으로만 채워진 문자열을 필터하지 못함.
if(request.isEmpty() || request.get("content").isBlank()) throw new IllegalArgumentException("댓글 내용은 필수입니다.");

String content = request.get("content");

Comment comment = Comment.builder()
.content(content)
.post(post)
.build();

Comment saved = commentRepository.save(comment);
return new CommentCreateResponseDto(saved);
}

@Transactional
public CommentUpdateResponseDto update(UUID commentId, Map<String, String> request) {
// 1. 댓글 존재 여부 확인
Comment comment = getComment(commentId);

// 2. 클라이언트가 전달한 데이터 여부 확인
// isBlank() 는 null, 빈문자열("")과 공백으로만 채워진 문자열을 검증하는 역할, isEmpty() 는 공백으로만 채워진 문자열을 필터하지 못함.
// if(HashMap 타입 참조변수 == null) 이 아닌 HashMap 타입 참조변수는 isEmpty() 로 null 체크해야하는 것 같음
if(request.isEmpty() || request.get("content").isBlank()) throw new IllegalArgumentException("댓글 내용은 필수입니다.");

String content = request.get("content");

if(!comment.getContent().equals(content)) {
comment.setContent(content);
}
Comment updateComment = commentRepository.save(comment);
return new CommentUpdateResponseDto(updateComment);
}

@Transactional
public DeleteCommentResponseDto delete(UUID commentId) {
Comment comment = getComment(commentId);
comment.delete();
Comment deleteComment = commentRepository.save(comment);
return new DeleteCommentResponseDto(deleteComment);
}

// 수정과 삭제 메서드에서 댓글 존재 확인 코드가 중복되어 메서드 추출함.
private Comment getComment(UUID commentId) {
return commentRepository.findById(commentId).orElseThrow(() -> new IllegalArgumentException("해당 댓글이 존재하지 않습니다."));
}
}
Loading