-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pr feat: question api #30
Changes from 24 commits
99a9349
2cc6c93
c41d52e
9acee5a
137071d
3fa8483
fc0f378
9b37163
1f85121
a2ce16d
8b2b8d5
bce03d4
df01186
d8ca0b0
a4e77dc
6c4be2e
73bc85d
bfc6327
2ac46ec
71af44b
a0ab8f9
51152cd
e1b7de4
8989472
4f1bd82
9f4720a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,13 +11,23 @@ | |
@Getter | ||
@MappedSuperclass | ||
@EntityListeners(AuditingEntityListener.class) | ||
public class BaseEntity extends BaseTimeEntity{ | ||
public class BaseEntity extends BaseTimeEntity { | ||
@CreatedBy | ||
@Column(updatable = false) | ||
private String createdBy; | ||
|
||
@LastModifiedBy | ||
private String lastModifiedBy; | ||
|
||
private boolean status; | ||
private boolean deleted; | ||
|
||
// 재활성화 - soft delete | ||
public void activate() { | ||
this.deleted = false; | ||
} | ||
|
||
// 비활성화 - soft delete | ||
public void deactivate() { | ||
this.deleted = true; | ||
} | ||
Comment on lines
+22
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. soft delete 개념에서 enum 타입만 생각했었는데 deleted로 객체의 재활성화, 비활성화 상태를 관리하니 좋은 것 같네용 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package com.api.ttoklip.domain.common.comment; | ||
|
||
import com.api.ttoklip.domain.common.base.BaseEntity; | ||
import com.api.ttoklip.domain.common.comment.editor.CommentEditor; | ||
import com.api.ttoklip.domain.question.post.domain.Question; | ||
import jakarta.persistence.DiscriminatorColumn; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Inheritance; | ||
import jakarta.persistence.InheritanceType; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) | ||
@DiscriminatorColumn | ||
public class Comment extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private String content; // 댓글 내용 | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "question_id") | ||
private Question question; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 한 개의 댓글 엔티티를 공유하기 때문에 null이 많아지는 문제가 향후 발생할 수도 있을것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 공통 댓글 엔티티에서 직접 연관관계 매핑을 하는 것이 아닌, 이를 상속 받는 Question Entity에서 QuestionComment Entity 클래스로 이동하도록 수정하겠습니다. |
||
|
||
// @ManyToOne(fetch = FetchType.LAZY) | ||
// @JoinColumn(name = "member_id") | ||
// private Member member; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "parent_id") | ||
private Comment parent; | ||
|
||
protected Comment(final String content, final Question question, final Comment parent) { | ||
this.content = content; | ||
this.question = question; | ||
this.parent = parent; | ||
} | ||
|
||
public CommentEditor.CommentEditorBuilder toEditor() { | ||
return CommentEditor.builder() | ||
.comment(content); | ||
} | ||
Comment on lines
+46
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 댓글을 편집하기 위해 빌더 패턴과 |
||
|
||
public void edit(final CommentEditor commentEditor) { | ||
this.content = commentEditor.getContent(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.api.ttoklip.domain.common.comment.dto.response; | ||
|
||
import com.api.ttoklip.domain.common.comment.Comment; | ||
import com.api.ttoklip.global.util.TimeUtil; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.time.LocalDateTime; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@Builder | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
public class CommentResponse { | ||
|
||
@Schema(description = "댓글 ID", example = "101") | ||
private Long commentId; | ||
|
||
@Schema(description = "댓글 내용", example = "댓글 내용 예시") | ||
private String commentContent; | ||
|
||
@Schema(description = "부모 댓글 ID (대댓글의 경우)", example = "1") | ||
private Long parentId; | ||
|
||
@Schema(description = "댓글 작성자", example = "댓글 작성자 예시") | ||
private String writer; | ||
|
||
@Schema(description = "댓글 작성 시간", example = "2024-01-11 11:00:00") | ||
private String writtenTime; | ||
|
||
|
||
public static CommentResponse from(final Comment questionComment) { | ||
LocalDateTime createdDate = questionComment.getCreatedDate(); | ||
String formatCreatedDate = TimeUtil.formatCreatedDate(createdDate); | ||
|
||
if (questionComment.getParent() == null) { | ||
return getCommentResponse(questionComment, null, formatCreatedDate); | ||
} | ||
|
||
return getCommentResponse(questionComment, questionComment.getParent().getId(), formatCreatedDate); | ||
} | ||
|
||
private static CommentResponse getCommentResponse(final Comment questionComment, final Long parentCommentId, | ||
final String formatCreatedDate) { | ||
return CommentResponse.builder() | ||
.commentId(questionComment.getId()) | ||
.commentContent(questionComment.getContent()) | ||
.parentId(parentCommentId) // 부모 댓글이 있는 경우 | ||
// .writer(questionComment.getMember().getName()) // ToDo Member Entity 생성 후 수정 | ||
.writtenTime(formatCreatedDate) | ||
.build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.api.ttoklip.domain.common.comment.editor; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.util.StringUtils; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class CommentEditor { | ||
|
||
private final String content; | ||
|
||
public static CommentEditorBuilder builder() { | ||
return new CommentEditorBuilder(); | ||
} | ||
public static class CommentEditorBuilder { | ||
private String content; | ||
|
||
CommentEditorBuilder() { | ||
} | ||
|
||
public CommentEditorBuilder comment(final String content) { | ||
if (StringUtils.hasText(content)) { | ||
this.content = content; | ||
} | ||
return this; | ||
} | ||
|
||
public CommentEditor build() { | ||
return new CommentEditor(content); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.api.ttoklip.domain.common.comment.repository; | ||
|
||
import com.api.ttoklip.domain.common.comment.Comment; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface CommentRepository extends JpaRepository<Comment, Long>, CommentRepositoryCustom { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.api.ttoklip.domain.common.comment.repository; | ||
|
||
import com.api.ttoklip.domain.common.comment.Comment; | ||
|
||
public interface CommentRepositoryCustom { | ||
Comment findByIdActivated(final Long commentId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.api.ttoklip.domain.common.comment.repository; | ||
|
||
import static com.api.ttoklip.domain.common.comment.QComment.comment; | ||
|
||
import com.api.ttoklip.domain.common.comment.Comment; | ||
import com.api.ttoklip.global.exception.ApiException; | ||
import com.api.ttoklip.global.exception.ErrorType; | ||
import com.querydsl.core.types.dsl.BooleanExpression; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
public class CommentRepositoryImpl implements CommentRepositoryCustom { | ||
|
||
private final JPAQueryFactory jpaQueryFactory; | ||
|
||
@Override | ||
public Comment findByIdActivated(final Long commentId) { | ||
Comment findComment = jpaQueryFactory | ||
.selectFrom(comment) | ||
.where( | ||
matchId(commentId), getCommentActivate() | ||
) | ||
.fetchOne(); | ||
return Optional.ofNullable(findComment) | ||
.orElseThrow(() -> new ApiException(ErrorType.COMMENT_NOT_FOUNT)); | ||
} | ||
|
||
private BooleanExpression matchId(final Long commentId) { | ||
return comment.id.eq(commentId); | ||
} | ||
|
||
private BooleanExpression getCommentActivate() { | ||
return comment.deleted.isFalse(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.api.ttoklip.domain.common.comment.service; | ||
|
||
import com.api.ttoklip.domain.common.comment.Comment; | ||
import com.api.ttoklip.domain.common.comment.dto.request.CommentEditRequest; | ||
import com.api.ttoklip.domain.common.comment.editor.CommentEditor; | ||
import com.api.ttoklip.domain.common.comment.editor.CommentEditor.CommentEditorBuilder; | ||
import com.api.ttoklip.domain.common.comment.repository.CommentRepository; | ||
import com.api.ttoklip.global.exception.ApiException; | ||
import com.api.ttoklip.global.exception.ErrorType; | ||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class CommentService { | ||
|
||
private final CommentRepository commentRepository; | ||
|
||
/* -------------------------------------------- CREATE -------------------------------------------- */ | ||
@Transactional | ||
public void register(final Comment comment) { | ||
commentRepository.save(comment); | ||
} | ||
/* -------------------------------------------- CREATE 끝 -------------------------------------------- */ | ||
|
||
|
||
/* -------------------------------------------- READ 부모 댓글 -------------------------------------------- */ | ||
public Optional<Comment> findParentComment(final Long parentCommentId) { | ||
if (parentCommentId != null) { | ||
return commentRepository.findById(parentCommentId); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
/* -------------------------------------------- READ 부모 댓글 끝 -------------------------------------------- */ | ||
|
||
/* -------------------------------------------- EDIT -------------------------------------------- */ | ||
@Transactional | ||
public void edit(final Long commentId, final CommentEditRequest request) { | ||
|
||
Comment comment = findComment(commentId); | ||
// ToDo 작성자가 맞는지 검증 필요 | ||
CommentEditor commentEditor = getCommentEditor(request, comment); | ||
comment.edit(commentEditor); | ||
} | ||
|
||
public Comment findComment(final Long commentId) { | ||
return commentRepository.findByIdActivated(commentId); | ||
} | ||
|
||
private CommentEditor getCommentEditor(final CommentEditRequest request, final Comment comment) { | ||
CommentEditorBuilder editorBuilder = comment.toEditor(); | ||
CommentEditor commentEditor = editorBuilder | ||
.comment(request.getComment()) | ||
.build(); | ||
return commentEditor; | ||
} | ||
|
||
/* -------------------------------------------- EDIT 끝 -------------------------------------------- */ | ||
|
||
/* -------------------------------------------- DELETE -------------------------------------------- */ | ||
@Transactional | ||
public void deleteById(final Long commentId) { | ||
// ToDo 본인이 썼는지 검증 과정 필요 | ||
Comment comment = findComment(commentId); | ||
comment.deactivate(); | ||
} | ||
/* -------------------------------------------- DELETE 끝 -------------------------------------------- */ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CATEGORY_NOT_FOUNT
오타가 있네요.CATEGORY_NOT_FOUND
로 수정하면 좋을 것 같습니다!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
엇 제가 놓친 부분이 있었네요 감사합니다!