-
Notifications
You must be signed in to change notification settings - Fork 2
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
[BE] feat: 내가 받은 리뷰 보기 기능 구현 #109
Changes from 13 commits
f522fd7
85ddfd2
a0ab043
b08db88
4f18dda
65a7917
a8f2528
022910c
453d1f4
92ea554
f2e1a0d
bf00a66
aa87cbd
4a491fd
6fcbc6d
010db8e
3a229bb
412523e
1499f37
bdc847b
af8cf09
1fb6465
c8e3cbe
065f752
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 |
---|---|---|
|
@@ -7,7 +7,6 @@ | |
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import jakarta.persistence.OneToOne; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
|
@@ -31,11 +30,11 @@ public class ReviewContent { | |
@JoinColumn(name = "review_id", nullable = false) | ||
private Review review; | ||
|
||
@OneToOne | ||
@ManyToOne | ||
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. 요구사항대로 잘 되었네요 👍🏻 |
||
@JoinColumn(name = "question_id", nullable = false) | ||
private Question question; | ||
|
||
@Column(name = "answer", nullable = false) | ||
@Column(name = "answer", nullable = false, length = MAX_ANSWER_LENGTH) | ||
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. DB에 글자수 조건 반영 좋네요! @Entity
public class ReviewerGroup {
@Column(name = "description", nullable = false)
private String description; 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. 헉스 그런데 제가 하면 혹시라도 conflict 날까봐 리팩터링 목록에 넣어두겠습니다! |
||
private String answer; | ||
|
||
public ReviewContent(Review review, Question question, String answer) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package reviewme.review.dto.response; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
|
||
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. 위쪽에 어떤 응답인지 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. 헉 속성에만 추가하고, dto 자체에는 안달아줬네요 😱 |
||
@Schema(description = "선택된 키워드 응답") | ||
public record ReceivedReviewKeywordsResponse( | ||
|
||
@Schema(description = "키워드 아이디") | ||
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. 다른 곳에서는 아이디를 "ID"로 표기했던 것 같은데, "아이디" 또는 "ID"로 통일해야 할 것 같아요. 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. 웁스 그렇네요!! 이슈 만들었습니다 |
||
long id, | ||
|
||
@Schema(description = "키워드 내용") | ||
String content | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package reviewme.review.dto.response; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.time.LocalDate; | ||
import java.util.List; | ||
|
||
@Schema(description = "리뷰 내용 응답") | ||
public record ReceivedReviewResponse( | ||
|
||
@Schema(description = "리뷰 아이디") | ||
long id, | ||
|
||
@Schema(description = "공개 여부") | ||
boolean isPublic, | ||
|
||
@Schema(description = "리뷰 작성일") | ||
LocalDate createdAt, | ||
|
||
@Schema(description = "응답 내용 미리보기") | ||
String contentPreview, | ||
|
||
@Schema(description = "리뷰어 그룹 정보") | ||
ReceivedReviewReviewerGroupResponse reviewerGroup, | ||
|
||
@Schema(description = "키워드") | ||
List<ReceivedReviewKeywordsResponse> keywords | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package reviewme.review.dto.response; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
|
||
@Schema(description = "리뷰어 그룹 정보 응답") | ||
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. 리뷰어 그룹 정보를 내보내는 DTO가 많기에 "리뷰 목록의 리뷰어 그룹 정보 응답"으로 컨텍스트를 추가해주는 건 어떨까요? 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. 스웨거에서 볼 때 JSON 안에서 감싸져서 보여질 것이기 때문에 별도의 맥락 추가는 없어도 괜찮을 것 같아요 ㅎㅎ(귀찮은 것 아님) |
||
public record ReceivedReviewReviewerGroupResponse( | ||
|
||
@Schema(description = "리뷰어 그룹 아이디") | ||
long id, | ||
|
||
@Schema(description = "리뷰어 그룹 이름") | ||
String name, | ||
|
||
@Schema(description = "리뷰어 그룹 썸네일 이미지 URL") | ||
String thumbnailUrl | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package reviewme.review.dto.response; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.util.List; | ||
|
||
@Schema(description = "내가 받은 리뷰 응답") | ||
public record ReceivedReviewsResponse( | ||
|
||
@Schema(description = "응답 개수") | ||
long size, | ||
|
||
@Schema(description = "마지막 리뷰 아이디") | ||
long lastReviewId, | ||
|
||
@Schema(description = "받은 리뷰 목록") | ||
List<ReceivedReviewResponse> reviews | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package reviewme.review.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
import reviewme.review.domain.Question; | ||
|
||
@Repository | ||
public interface QuestionRepository extends JpaRepository<Question, Long> { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
package reviewme.review.repository; | ||
|
||
import java.util.List; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.stereotype.Repository; | ||
import reviewme.member.domain.Member; | ||
import reviewme.member.domain.ReviewerGroup; | ||
|
@@ -15,4 +17,15 @@ public interface ReviewRepository extends JpaRepository<Review, Long> { | |
default Review getReviewById(Long id) { | ||
return findById(id).orElseThrow(ReviewNotFoundException::new); | ||
} | ||
|
||
@Query(""" | ||
SELECT r | ||
FROM Review r | ||
WHERE r.reviewee.id = :revieweeId | ||
AND r.id < :lastViewedReviewId | ||
ORDER BY r.createdAt DESC | ||
LIMIT :size | ||
""" | ||
) | ||
List<Review> findAllByRevieweeBeforeLastViewedReviewId(long revieweeId, long lastViewedReviewId, int size); | ||
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.
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. 음~ 쿼리를 썼으니 JPA가 제시하는 이름 형식을 따르지 않아도 된다는 말씀이군요! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,10 +10,13 @@ | |
import reviewme.member.domain.Member; | ||
import reviewme.member.domain.ReviewerGroup; | ||
import reviewme.member.repository.MemberRepository; | ||
import reviewme.member.repository.ReviewerGroupRepository; | ||
import reviewme.review.domain.Review; | ||
import reviewme.review.domain.ReviewContent; | ||
import reviewme.review.dto.request.CreateReviewRequest; | ||
import reviewme.review.dto.response.ReceivedReviewKeywordsResponse; | ||
import reviewme.review.dto.response.ReceivedReviewResponse; | ||
import reviewme.review.dto.response.ReceivedReviewReviewerGroupResponse; | ||
import reviewme.review.dto.response.ReceivedReviewsResponse; | ||
import reviewme.review.dto.response.ReviewDetailResponse; | ||
import reviewme.review.dto.response.ReviewDetailReviewContentResponse; | ||
import reviewme.review.dto.response.ReviewDetailReviewerGroupResponse; | ||
|
@@ -25,9 +28,9 @@ | |
@RequiredArgsConstructor | ||
public class ReviewService { | ||
|
||
public static final int REVIEW_CONTENT_PREIVEW_MAX_LENGHT = 150; | ||
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. 상수 필드 띄워주세요!
nayonsoso marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private final ReviewRepository reviewRepository; | ||
private final MemberRepository memberRepository; | ||
private final ReviewerGroupRepository reviewerGroupRepository; | ||
private final ReviewContentRepository reviewContentRepository; | ||
private final KeywordRepository keywordRepository; | ||
|
||
|
@@ -54,7 +57,8 @@ public ReviewDetailResponse findReview(long reviewId, long memberId) { | |
reviewerGroup.getDescription(), | ||
reviewerGroup.getThumbnailUrl() | ||
); | ||
List<ReviewDetailReviewContentResponse> reviewContentResponses = reviewContents.stream() | ||
List<ReviewDetailReviewContentResponse> reviewContentResponses = reviewContents | ||
.stream() | ||
.map(content -> new ReviewDetailReviewContentResponse( | ||
content.getQuestion(), | ||
content.getAnswer() | ||
|
@@ -75,4 +79,50 @@ public ReviewDetailResponse findReview(long reviewId, long memberId) { | |
keywordContents | ||
); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public ReceivedReviewsResponse findMyReceivedReview(long memberId, long lastReviewId, int size) { | ||
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.
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. ! |
||
List<Review> reviews = reviewRepository.findAllByRevieweeBeforeLastViewedReviewId( | ||
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. 이제 개행 안해도 되겠네요~ |
||
memberId, lastReviewId, size); | ||
|
||
int totalSize = reviews.size(); | ||
if (totalSize == 0) { | ||
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. 이 부분에 대한 분기가 필요한가요? 어차피 마지막 값이 나오지 않는다면 더이상 요청을 하지 않을 것이라고 생각했어요. 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. 분기는 필요할 것 같은게요!
return new ReceivedReviewsResponse(
reviews.size(),
reviews.get(totalSize - 1).getId(), // ❗️❗️ 이부분에서 IndexOutOfBound 발생
reviews.stream()
.map(review -> new ReceivedReviewResponse(
review.getId(),
review.isPublic(),
review.getCreatedAt().toLocalDate(),
getReviewContentPreview(review),
new ReceivedReviewReviewerGroupResponse(
review.getReviewerGroup().getId(),
review.getReviewerGroup().getGroupName(),
review.getReviewerGroup().getThumbnailUrl()
),
getKeywordResponse(review)))
.toList()); 입니다. ieEmpty() 부분은 적용하겠습니다! |
||
return new ReceivedReviewsResponse(0, 0, List.of()); | ||
} | ||
|
||
return new ReceivedReviewsResponse( | ||
reviews.size(), | ||
reviews.get(totalSize - 1).getId(), | ||
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. Java 21 절실하네요 🤔 |
||
reviews.stream() | ||
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. 인덴트가 많아지니 따로 변수로 뽑아도 좋겠네요! 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. 음 new XXXResponse 들이 다 map 안에서 사용되는 것들이라 분리한다면 함수로 분리해줘야 할 것 같네요! 일단 private 함수로 만들어주긴 했는데, 서비스 코드에서 dto 를 만들기 위해 필요한 함수가 많아져서 dto 안에 도메인 -> dto 함수를 만드는 것도 고려해볼 수 있는 시점 같아요 |
||
.map(review -> new ReceivedReviewResponse( | ||
review.getId(), | ||
review.isPublic(), | ||
review.getCreatedAt().toLocalDate(), | ||
getReviewContentPreview(review), | ||
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. (개인적인 의견)
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. @donghoony 👍👍 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. 따로 값 객체를 만들기보다, |
||
new ReceivedReviewReviewerGroupResponse( | ||
review.getReviewerGroup().getId(), | ||
review.getReviewerGroup().getGroupName(), | ||
review.getReviewerGroup().getThumbnailUrl() | ||
), | ||
getKeywordResponse(review))) | ||
.toList()); | ||
} | ||
|
||
private String getReviewContentPreview(Review review) { | ||
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. 이건 ReviewContent의 책임으로 있어도 괜찮을 것 같은데 어떤가용? 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.
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. 옮겼습니다! 날카로우시네요 ㅎ0ㅎ |
||
String firstContentAnswer = reviewContentRepository.findAllByReviewId(review.getId()) | ||
.get(0) | ||
.getAnswer(); | ||
return firstContentAnswer.substring(0, REVIEW_CONTENT_PREIVEW_MAX_LENGHT); | ||
} | ||
|
||
private List<ReceivedReviewKeywordsResponse> getKeywordResponse(Review review) { | ||
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.
|
||
return review.getKeywords().getKeywordIds() | ||
.stream() | ||
.map(keywordRepository::getKeywordById) | ||
.map(keyword -> new ReceivedReviewKeywordsResponse( | ||
keyword.getId(), | ||
keyword.getContent() | ||
)) | ||
.toList(); | ||
} | ||
} |
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.
우선은 그냥 단순히 특정 회원의 리뷰만 조회한다고 생각하면 될까요?
(누구든지 memberId를 넣으면 다른 사람의 리뷰를 조회 가능!)
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.
그춍.. 사실 목표한 기능은 '내가 받은 리뷰 보기'이지만
로그인 기능이 없고, memberId 로 로그인한다고 가정하고 있는 상황이니깐요😓
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.
다음 리팩터링 사항 논의 때 고려해보죠~