ProductDetailResponse와 ProductSummaryResponse가 거의 똑같은 구조를 가지고 있어 중복이 심하기 때문에 통합을 해준다.
그 후에 상품 생성 시간과 수정 시간을 응답에 넣어준다.
public class UserProfileDto {
@Builder
@Schema(description = "판매 내역 페이지 응답")
public record SellingHistoryResponse(
@Schema(description = "판매 중인 상품 목록")
List<ProductDto.ProductResponse> activeProducts,
@Schema(description = "판매 완료된 상품 목록")
List<ProductDto.ProductResponse> soldProducts,
@Schema(description = "총 상품 수", example = "10")
int totalProductCount
) {}
@Builder
@Schema(description = "구매 내역 페이지 응답")
public record PurchaseHistoryResponse(
@Schema(description = "구매 내역 목록")
List<ProductDto.ProductResponse> purchases,
@Schema(description = "총 구매 수", example = "5")
int totalPurchaseCount
) {}
}
UserDto에서는 ProductResponse을 가져와서 상품들을 보여주게 된다.
ProductDetailResponse로 작성한 반환 타입을 모두 ProductDto.ProductResponse로 변경해준다.
서비스 클래스들의 반환 타입도 ProductDto.ProductResponse로 변경해준다.
// 통합된 상품 응답 DTO - 모든 API에서 사용
@Builder
@Schema(description = "상품 응답")
public record ProductResponse(
@Schema(description = "상품 ID", example = "1")
Long id,
@Schema(description = "상품명", example = "새 노트북")
String name,
@Schema(description = "상품 설명", example = "거의 사용하지 않은 노트북입니다.")
String description,
@Schema(description = "가격", example = "1000000")
Long price,
@Schema(description = "재고 수량", example = "1")
Integer stock,
@Schema(description = "카테고리 표시명", example = "전자기기")
String category,
@Schema(description = "상품 상태", example = "판매중")
String status,
@Schema(description = "썸네일 이미지 URL", example = "https://example.com/thumbnail.jpg")
String thumbnailUrl,
@Schema(description = "이미지 URL 목록")
List<String> imageUrls,
@Schema(description = "판매자 ID", example = "123")
Long sellerId,
@Schema(description = "판매자 이름", example = "홍길동")
String sellerName,
@Schema(description = "상품 등록일", example = "2025-01-15T10:30:00")
LocalDateTime createdDate,
@Schema(description = "상품 수정일", example = "2025-01-16T14:20:00")
LocalDateTime updatedDate,
@Schema(description = "조회수", example = "42")
Long viewCount,
@Schema(description = "관심 등록 수", example = "7")
Long wishlistCount,
@Schema(description = "현재 사용자의 관심 등록 여부", example = "true")
boolean isWishlisted
) {
// 완전한 정보로 생성 (상세 조회, 목록 조회용)
public static ProductResponse from(Product product, Long viewCount, Long wishlistCount, boolean isWishlisted) {
return ProductResponse.builder()
.id(product.getId())
.name(product.getName())
.description(product.getDescription())
.price(product.getPrice())
.stock(product.getStock())
.category(product.getCategory().getDisplayName())
.status(product.getStatus().getDisplayName())
.thumbnailUrl(product.getRepresentativeThumbnailUrl())
.imageUrls(product.getImages().stream()
.map(ProductImage::getImageUrl)
.collect(Collectors.toList()))
.sellerId(product.getSeller().getId())
.sellerName(product.getSeller().getName())
.createdDate(product.getCreatedDate())
.updatedDate(product.getUpdatedDate())
.viewCount(viewCount != null ? viewCount : 0L)
.wishlistCount(wishlistCount != null ? wishlistCount : 0L)
.isWishlisted(isWishlisted)
.build();
}
// 기본 정보만으로 생성 (등록, 수정 결과용 - 통계 정보 없음)
public static ProductResponse from(Product product) {
return from(product, 0L, 0L, false);
}
}
상품 상제 정보와 관련된 응답을 하나의 DTO로 사용할 수 있게 통합한 뒤에 생성 시간과, 수정 시간에 대한 정보를 넣어준다.
@Schema(description = "상품과 관련 통계 정보 포함 DTO")
public record ProductWithStatsDto(
@Schema(description = "상품 정보", required = true)
Product product,
@Schema(description = "상품 조회수", example = "42")
Long viewCount,
@Schema(description = "관심 등록 수", example = "7")
Long wishlistCount,
@Schema(description = "현재 사용자의 관심 등록 여부", example = "true")
boolean isWishlisted
) {
public ProductWithStatsDto {
// null 체크 및 기본값 설정
viewCount = viewCount != null ? viewCount : 0L;
wishlistCount = wishlistCount != null ? wishlistCount : 0L;
}
public ProductDto.ProductResponse toProductResponse() {
return ProductDto.ProductResponse.from(
product,
viewCount,
wishlistCount,
isWishlisted
);
}
}
ProductResponse로 반환값을 변경해준다.
ProductResponse로 반환값을 변경해준다.
ProductResponse로 반환값을 변경해준다.
ProductResponse로 반환값을 변경해준 뒤 메서드를 수정해준다.
public List<ProductDto.ProductResponse> getUserWishlistDetailDto(Long userId) {
User user = getUser(userId);
return productWishlistRepository.findAllByUser(user).stream()
.map(wishlist -> {
Product product = wishlist.getProduct();
Long viewCount = viewService.getViewCount(product.getId());
Long wishlistCount = getWishlistCount(product.getId());
// 이미 위시리스트에서 가져온 상품이므로 무조건 true
boolean isWishlisted = true;
return ProductDto.ProductResponse.from(product, viewCount, wishlistCount, isWishlisted);
})
.toList();
}
이미 위시리스트에 있는 상품이니 항상 true로 가져온다.
ProductResponse로 반환값을 변경해준다.
// 상품 목록 조회
public Page<ProductDto.ProductResponse> getFilteredProducts(ProductCategory category, String keyword, ProductStatus status,
Long minPrice, Long maxPrice, ProductSort sort,
Pageable pageable, Long userId) {
return productRepository.findProductsWithFilters(category, keyword, status, minPrice, maxPrice, sort, pageable, userId)
.map(ProductWithStatsDto::toProductResponse);
}
DTO 변경하는 로직을 변경해준다.