Skip to content
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

특정 사용자가 작성한 리뷰 목록 조회 API 추가 #107

Merged
merged 7 commits into from
Jan 11, 2024
18 changes: 18 additions & 0 deletions src/docs/asciidoc/api-doc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,24 @@ include::{snippets}/user-controller-test/respond_200_when_read_bookmarked_produc
==== Sample Response
include::{snippets}/user-controller-test/respond_200_when_read_bookmarked_product_list_successfully/http-response.adoc[]

=== 1-11. 특정 사용자의 리뷰 목록 조회
==== Request Fields
include::{snippets}/user-controller-test/respond_200_when_read_user_review_list_successfully/request-fields.adoc[]
==== 정렬 기준 항목
|===
| sortBy 값 | 정렬 기준 | 비고

| LATEST | 최신순 | 정렬 기준 미지정시 기본값
| LIKE | 좋아요순 |
| RATING | 별점순 |
|===
==== Sample Request
include::{snippets}/user-controller-test/respond_200_when_read_user_review_list_successfully/http-request.adoc[]
==== Response Fields
include::{snippets}/user-controller-test/respond_200_when_read_user_review_list_successfully/response-fields.adoc[]
==== Sample Response
include::{snippets}/user-controller-test/respond_200_when_read_user_review_list_successfully/http-response.adoc[]

== 2. 인증
=== 2-1. 로그인
==== Request Fields
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/cvsgo/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ public void addInterceptors(InterceptorRegistry registry) {
.addPathPatterns("/**")
.excludePathPatterns("/", "/docs/**", "/*.ico", "/api/auth/login", "/api/users",
"/api/tags", "/api/users/emails/*/exists", "/api/users/nicknames/*/exists",
"/api/products", "/api/products/*", "/api/products/*/tags");
"/api/products", "/api/products/*", "/api/products/*/tags", "/api/users/*/reviews");
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/cvsgo/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import com.cvsgo.dto.SuccessResponse;
import com.cvsgo.dto.product.ReadProductResponseDto;
import com.cvsgo.dto.product.ReadUserProductRequestDto;
import com.cvsgo.dto.review.ReadUserReviewResponseDto;
import com.cvsgo.dto.review.ReviewSortBy;
import com.cvsgo.dto.user.SignUpRequestDto;
import com.cvsgo.dto.user.SignUpResponseDto;
import com.cvsgo.dto.user.UpdateUserRequestDto;
import com.cvsgo.dto.user.UserResponseDto;
import com.cvsgo.entity.User;
import com.cvsgo.service.ProductService;
import com.cvsgo.service.ReviewService;
import com.cvsgo.service.UserService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -33,8 +36,11 @@
public class UserController {

private final UserService userService;

private final ProductService productService;

private final ReviewService reviewService;

@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED)
public SuccessResponse<SignUpResponseDto> register(
Expand Down Expand Up @@ -92,4 +98,11 @@ public SuccessResponse<Page<ReadProductResponseDto>> readBookmarkedProductList(
productService.readBookmarkedProductList(userId, request, pageable));
}

@GetMapping("/users/{userId}/reviews")
public SuccessResponse<Page<ReadUserReviewResponseDto>> readUserReviewList(@LoginUser User loginUser,
@PathVariable Long userId, ReviewSortBy sortBy, Pageable pageable) {
return SuccessResponse.from(
reviewService.readUserReviewList(loginUser, userId, sortBy, pageable));
}

}
2 changes: 0 additions & 2 deletions src/main/java/com/cvsgo/dto/review/ReadReviewRequestDto.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.cvsgo.dto.review;

import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import java.util.List;
import lombok.Getter;

Expand Down
61 changes: 61 additions & 0 deletions src/main/java/com/cvsgo/dto/review/ReadUserReviewQueryDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.cvsgo.dto.review;

import com.cvsgo.entity.ProductBookmark;
import com.cvsgo.entity.ReviewLike;
import com.querydsl.core.annotations.QueryProjection;
import java.time.LocalDateTime;
import lombok.Getter;

@Getter
public class ReadUserReviewQueryDto {

private final Long reviewId;

private final Long productId;

private final String productName;

private final String manufacturerName;

private final String productImageUrl;

private final Long reviewerId;

private final String reviewerNickname;

private final String reviewerProfileImageUrl;

private final Long likeCount;

private final Integer rating;

private final String reviewContent;

private final Boolean isReviewLiked;

private final Boolean isProductBookmarked;

private final LocalDateTime createdAt;

@QueryProjection
public ReadUserReviewQueryDto(Long reviewId, Long productId, String productName,
String manufacturerName, String productImageUrl, Long reviewerId, String reviewerNickname,
String reviewerProfileImageUrl, Long likeCount, Integer rating,
String reviewContent, LocalDateTime createdAt, ReviewLike reviewLike,
ProductBookmark productBookmark) {
this.reviewId = reviewId;
this.productId = productId;
this.productName = productName;
this.manufacturerName = manufacturerName;
this.productImageUrl = productImageUrl;
this.reviewerId = reviewerId;
this.reviewerNickname = reviewerNickname;
this.reviewerProfileImageUrl = reviewerProfileImageUrl;
this.likeCount = likeCount;
this.rating = rating;
this.reviewContent = reviewContent;
this.createdAt = createdAt;
this.isReviewLiked = reviewLike != null;
this.isProductBookmarked = productBookmark != null;
}
}
86 changes: 86 additions & 0 deletions src/main/java/com/cvsgo/dto/review/ReadUserReviewResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.cvsgo.dto.review;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Builder;
import lombok.Getter;

@Getter
public class ReadUserReviewResponseDto {

private final Long productId;

private final String productName;

private final String productManufacturer;

private final String productImageUrl;

private final Long reviewId;

private final Long reviewerId;

private final String reviewerNickname;

private final String reviewerProfileImageUrl;

private final Long reviewLikeCount;

private final Integer reviewRating;

private final String reviewContent;

private final Boolean isReviewLiked;

private final Boolean isProductBookmarked;

private final List<String> reviewImageUrls;

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
private final LocalDateTime createdAt;

@Builder
public ReadUserReviewResponseDto(Long productId, String productName, String productManufacturer,
String productImageUrl, Long reviewId, Long reviewerId, String reviewerNickname,
String reviewerProfileImageUrl,
Long reviewLikeCount, Integer reviewRating, String reviewContent, Boolean isReviewLiked,
Boolean isProductBookmarked, List<String> reviewImageUrls, LocalDateTime createdAt) {
this.productId = productId;
this.productName = productName;
this.productManufacturer = productManufacturer;
this.productImageUrl = productImageUrl;
this.reviewId = reviewId;
this.reviewerId = reviewerId;
this.reviewerNickname = reviewerNickname;
this.reviewerProfileImageUrl = reviewerProfileImageUrl;
this.reviewLikeCount = reviewLikeCount;
this.reviewRating = reviewRating;
this.reviewContent = reviewContent;
this.isReviewLiked = isReviewLiked;
this.isProductBookmarked = isProductBookmarked;
this.reviewImageUrls = reviewImageUrls;
this.createdAt = createdAt;
}

public static ReadUserReviewResponseDto of(ReadUserReviewQueryDto readUserReviewQueryDto,
List<String> reviewImageUrls) {
return ReadUserReviewResponseDto.builder()
.productName(readUserReviewQueryDto.getProductName())
.productId(readUserReviewQueryDto.getProductId())
.reviewContent(readUserReviewQueryDto.getReviewContent())
.productImageUrl(readUserReviewQueryDto.getProductImageUrl())
.productManufacturer(readUserReviewQueryDto.getManufacturerName())
.reviewId(readUserReviewQueryDto.getReviewId())
.reviewerId(readUserReviewQueryDto.getReviewerId())
.reviewerNickname(readUserReviewQueryDto.getReviewerNickname())
.reviewerProfileImageUrl(readUserReviewQueryDto.getReviewerProfileImageUrl())
.reviewRating(readUserReviewQueryDto.getRating())
.reviewLikeCount(readUserReviewQueryDto.getLikeCount())
.createdAt(readUserReviewQueryDto.getCreatedAt())
.isProductBookmarked(readUserReviewQueryDto.getIsProductBookmarked())
.isReviewLiked(readUserReviewQueryDto.getIsReviewLiked())
.reviewImageUrls(reviewImageUrls)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.cvsgo.dto.review.ReadProductReviewRequestDto;
import com.cvsgo.dto.review.ReadReviewQueryDto;
import com.cvsgo.dto.review.ReadReviewRequestDto;
import com.cvsgo.dto.review.ReadUserReviewQueryDto;
import com.cvsgo.dto.review.ReviewSortBy;
import com.cvsgo.entity.User;
import java.util.List;
import org.springframework.data.domain.Pageable;
Expand All @@ -18,6 +20,11 @@ List<ReadReviewQueryDto> findAllByFilter(User loginUser, ReadReviewRequestDto fi
List<ReadProductReviewQueryDto> findAllByProductIdAndFilter(User loginUser, Long productId,
ReadProductReviewRequestDto filter, Pageable pageable);

List<ReadUserReviewQueryDto> findAllByUser(User loginUser, User reviewer, ReviewSortBy sortBy,
Pageable pageable);

Long countByProductIdAndFilter(Long productId, ReadProductReviewRequestDto filter);

Long countByUser(User user);

}
45 changes: 45 additions & 0 deletions src/main/java/com/cvsgo/repository/ReviewCustomRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

import com.cvsgo.dto.review.QReadProductReviewQueryDto;
import com.cvsgo.dto.review.QReadReviewQueryDto;
import com.cvsgo.dto.review.QReadUserReviewQueryDto;
import com.cvsgo.dto.review.ReadProductReviewQueryDto;
import com.cvsgo.dto.review.ReadProductReviewRequestDto;
import com.cvsgo.dto.review.ReadReviewQueryDto;
import com.cvsgo.dto.review.ReadUserReviewQueryDto;
import com.cvsgo.dto.review.ReviewSortBy;
import com.cvsgo.dto.review.ReadReviewRequestDto;
import com.cvsgo.entity.User;
Expand Down Expand Up @@ -106,6 +108,38 @@ public List<ReadProductReviewQueryDto> findAllByProductIdAndFilter(User loginUse
.fetch();
}

public List<ReadUserReviewQueryDto> findAllByUser(User loginUser, User reviewer,
ReviewSortBy sortBy, Pageable pageable) {
return queryFactory.select(new QReadUserReviewQueryDto(
review.id,
product.id,
product.name,
product.manufacturer.name,
product.imageUrl,
review.user.id,
review.user.nickname,
review.user.profileImageUrl,
review.likeCount,
review.rating,
review.content,
review.createdAt,
reviewLike,
productBookmark))
.from(review)
.join(user).on(user.eq(review.user))
.join(product).on(review.product.eq(product))
.leftJoin(reviewLike).on(reviewLike.review.eq(review).and(reviewLikeUserEq(reviewer)))
.leftJoin(productBookmark)
.on(productBookmark.product.eq(review.product).and(productBookmarkUserEq(loginUser)))
.where(
review.user.eq(reviewer)
)
.orderBy(sortBy(sortBy))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

public Long countByProductIdAndFilter(Long productId, ReadProductReviewRequestDto filter) {
return queryFactory.select(review.count())
.from(review)
Expand All @@ -119,6 +153,17 @@ public Long countByProductIdAndFilter(Long productId, ReadProductReviewRequestDt
.fetchOne();
}

public Long countByUser(User reviewer) {
return queryFactory.select(review.count())
.from(review)
.join(user).on(user.eq(review.user))
.join(product).on(review.product.eq(product))
.where(
review.user.eq(reviewer)
)
.fetchOne();
}

private OrderSpecifier<?> sortBy(ReviewSortBy sortBy) {
return sortBy != null ?
switch (sortBy) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/cvsgo/repository/ReviewRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface ReviewRepository extends JpaRepository<Review, Long>, ReviewCus

boolean existsByProductAndUser(Product product, User user);

long countByUser(User user);
Long countByUser(User user);

@Lock(LockModeType.OPTIMISTIC)
@Query(value = "select p from Review p where p.id = :id")
Expand Down
Loading