feat : 리뷰 조회 추가
This commit is contained in:
parent
2eefb269e6
commit
458f532b31
@ -17,6 +17,7 @@ public interface ExternalReviewPort {
|
||||
* 최근 리뷰 데이터 조회
|
||||
*/
|
||||
List<String> getRecentReviews(Long storeId, Integer days);
|
||||
|
||||
|
||||
/**
|
||||
* 리뷰 개수 조회
|
||||
|
||||
@ -96,7 +96,29 @@ public class ReviewInteractor implements CreateReviewUseCase, DeleteReviewUseCas
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ReviewListResponse> getStoreRecentReviews(Long storeId, Integer page, Integer size, Integer days) {
|
||||
Pageable pageable = PageRequest.of(page != null ? page : 0, size == null || size == 0 ? 1000 : size);
|
||||
|
||||
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(days);
|
||||
Page<Review> reviews = reviewRepository.findRecentReviewsByStoreId(storeId, pageable, cutoffDate);
|
||||
|
||||
return reviews.stream()
|
||||
.filter(review -> review.getStatus() == ReviewStatus.ACTIVE)
|
||||
.map(review -> ReviewListResponse.builder()
|
||||
.reviewId(review.getId())
|
||||
.memberNickname(review.getMemberNickname())
|
||||
.rating(review.getRating())
|
||||
.content(review.getContent())
|
||||
.imageUrls(review.getImageUrls())
|
||||
.likeCount(review.getLikeCount())
|
||||
.dislikeCount(review.getDislikeCount())
|
||||
.createdAt(review.getCreatedAt())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ReviewDetailResponse getReviewDetail(Long reviewId) {
|
||||
|
||||
@ -15,6 +15,11 @@ public interface GetReviewUseCase {
|
||||
* 매장 리뷰 목록 조회
|
||||
*/
|
||||
List<ReviewListResponse> getStoreReviews(Long storeId, Integer page, Integer size);
|
||||
|
||||
/**
|
||||
* 매장 최근 리뷰 목록 조회
|
||||
*/
|
||||
List<ReviewListResponse> getStoreRecentReviews(Long storeId, Integer page, Integer size, Integer days);
|
||||
|
||||
/**
|
||||
* 리뷰 상세 조회
|
||||
|
||||
@ -3,7 +3,9 @@ package com.ktds.hi.review.biz.usecase.out;
|
||||
import com.ktds.hi.review.biz.domain.Review;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -34,6 +36,11 @@ public interface ReviewRepository {
|
||||
*/
|
||||
Page<Review> findReviewsByStoreIdOrderByCreatedAtDesc(Long storeId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 매장 ID와 일자 데이터로 최근 리뷰 목록 조회
|
||||
*/
|
||||
Page<Review> findRecentReviewsByStoreId(Long storeId, Pageable pageable, @Param("cutoffDate") LocalDateTime cutoffDate);
|
||||
|
||||
/**
|
||||
* 회원 ID로 리뷰 목록 조회
|
||||
*/
|
||||
|
||||
@ -52,6 +52,24 @@ public class ReviewController {
|
||||
List<ReviewListResponse> reviews = getReviewUseCase.getStoreReviews(storeId, page, size);
|
||||
return ResponseEntity.ok(reviews);
|
||||
}
|
||||
|
||||
/**
|
||||
* 최근 매장 리뷰 목록 조회 API
|
||||
*/
|
||||
@GetMapping("/stores/recent/{storeId}")
|
||||
@Operation(summary = "매장 최근 리뷰 목록 조회", description = "특정 매장의 최근 리뷰 목록을 조회합니다.")
|
||||
public ResponseEntity<List<ReviewListResponse>> getStoreRecentReviews(
|
||||
@PathVariable Long storeId,
|
||||
@RequestParam(defaultValue = "0") Integer page,
|
||||
@RequestParam(defaultValue = "0") Integer size,
|
||||
@RequestParam Integer days
|
||||
) {
|
||||
|
||||
List<ReviewListResponse> reviews = getReviewUseCase.getStoreRecentReviews(storeId, page, size, days);
|
||||
return ResponseEntity.ok(reviews);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 리뷰 상세 조회 API
|
||||
|
||||
@ -10,6 +10,7 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -47,7 +48,17 @@ public class ReviewRepositoryAdapter implements ReviewRepository {
|
||||
pageable);
|
||||
return entities.map(this::toDomain);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Page<Review> findRecentReviewsByStoreId(Long storeId, Pageable pageable,
|
||||
LocalDateTime cutoffDate) {
|
||||
|
||||
Page<ReviewEntity> entities = reviewJpaRepository.findRecentReviewsByStoreId(storeId, ReviewStatus.ACTIVE,
|
||||
cutoffDate,pageable);
|
||||
return entities.map(this::toDomain);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Review> findReviewsByMemberId(Long memberId, Pageable pageable) {
|
||||
Page<ReviewEntity> entities = reviewJpaRepository.findByMemberIdAndStatus(memberId, ReviewStatus.ACTIVE, pageable);
|
||||
|
||||
@ -1,46 +1,58 @@
|
||||
package com.ktds.hi.review.infra.gateway.repository;
|
||||
|
||||
import com.ktds.hi.review.biz.domain.ReviewStatus;
|
||||
import com.ktds.hi.review.infra.gateway.entity.ReviewEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 리뷰 JPA 리포지토리 인터페이스
|
||||
* 리뷰 데이터의 CRUD 작업을 담당
|
||||
*/
|
||||
@Repository
|
||||
public interface ReviewJpaRepository extends JpaRepository<ReviewEntity, Long> {
|
||||
|
||||
/**
|
||||
* 매장 ID와 상태로 리뷰 목록 조회
|
||||
*/
|
||||
Page<ReviewEntity> findByStoreIdAndStatus(Long storeId, ReviewStatus status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 회원 ID와 상태로 리뷰 목록 조회
|
||||
*/
|
||||
Page<ReviewEntity> findByMemberIdAndStatus(Long memberId, ReviewStatus status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 리뷰 ID와 회원 ID로 리뷰 조회
|
||||
*/
|
||||
Optional<ReviewEntity> findByIdAndMemberId(Long id, Long memberId);
|
||||
|
||||
|
||||
/**
|
||||
* ✅ 수정: 매장ID + 내용으로 중복 리뷰 체크
|
||||
*/
|
||||
boolean existsByStoreIdAndContent(Long storeId, String content);
|
||||
|
||||
/**
|
||||
* 대안: 외부 닉네임으로만 중복 체크 (더 간단한 방법)
|
||||
*/
|
||||
// boolean existsByStoreIdAndExternalNickname(Long storeId, String externalNickname);
|
||||
}
|
||||
package com.ktds.hi.review.infra.gateway.repository;
|
||||
|
||||
import com.ktds.hi.review.biz.domain.ReviewStatus;
|
||||
import com.ktds.hi.review.infra.gateway.entity.ReviewEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 리뷰 JPA 리포지토리 인터페이스
|
||||
* 리뷰 데이터의 CRUD 작업을 담당
|
||||
*/
|
||||
@Repository
|
||||
public interface ReviewJpaRepository extends JpaRepository<ReviewEntity, Long> {
|
||||
|
||||
/**
|
||||
* 매장 ID와 상태로 리뷰 목록 조회
|
||||
*/
|
||||
Page<ReviewEntity> findByStoreIdAndStatus(Long storeId, ReviewStatus status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 회원 ID와 상태로 리뷰 목록 조회
|
||||
*/
|
||||
Page<ReviewEntity> findByMemberIdAndStatus(Long memberId, ReviewStatus status, Pageable pageable);
|
||||
|
||||
@Query("SELECT r FROM ReviewEntity r WHERE r.storeId = :storeId " +
|
||||
"AND r.status = :status " +
|
||||
"AND (CAST(:cutoffDate AS TIMESTAMP) IS NULL OR r.createdAt >= :cutoffDate) " +
|
||||
"ORDER BY r.createdAt DESC")
|
||||
Page<ReviewEntity> findRecentReviewsByStoreId(
|
||||
@Param("storeId") Long storeId,
|
||||
@Param("status") ReviewStatus status,
|
||||
@Param("cutoffDate") LocalDateTime cutoffDate,
|
||||
Pageable pageable
|
||||
);
|
||||
|
||||
/**
|
||||
* 리뷰 ID와 회원 ID로 리뷰 조회
|
||||
*/
|
||||
Optional<ReviewEntity> findByIdAndMemberId(Long id, Long memberId);
|
||||
|
||||
|
||||
/**
|
||||
* ✅ 수정: 매장ID + 내용으로 중복 리뷰 체크
|
||||
*/
|
||||
boolean existsByStoreIdAndContent(Long storeId, String content);
|
||||
|
||||
/**
|
||||
* 대안: 외부 닉네임으로만 중복 체크 (더 간단한 방법)
|
||||
*/
|
||||
// boolean existsByStoreIdAndExternalNickname(Long storeId, String externalNickname);
|
||||
}
|
||||
|
||||
@ -5,4 +5,7 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-webflux'
|
||||
implementation 'com.azure:azure-messaging-eventhubs:5.15.0'
|
||||
|
||||
implementation 'com.azure:azure-storage-blob:12.22.1'
|
||||
implementation 'com.azure:azure-storage-common:12.21.1'
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package com.ktds.hi.store.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.azure.storage.blob.BlobServiceClient;
|
||||
import com.azure.storage.blob.BlobServiceClientBuilder;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Azure Blob Storage 설정
|
||||
*
|
||||
* @author 하이오더 개발팀
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
// @Configuration
|
||||
public class AzureStorageConfig {
|
||||
|
||||
@Value("${azure.storage.connection-string}")
|
||||
private String connectionString;
|
||||
|
||||
@Bean
|
||||
public BlobServiceClient blobServiceClient() {
|
||||
log.info("Azure Blob Storage 클라이언트 초기화");
|
||||
return new BlobServiceClientBuilder()
|
||||
.connectionString(connectionString)
|
||||
.buildClient();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user