Skip to content

Commit

Permalink
feat: 통계 top5 price, quantity 상품 조회 기능 추가 (#224)
Browse files Browse the repository at this point in the history
* feat: 가장 많이 팔린 & 누적 판매량 top5 조회 기능 추가

* refactor: StatisticsRedis life cycle 수정

* refactor: StatisticsRepository 의존성 분리

* refactor: dto access level 수정

* refactor: Liquor Table join query 추가

* refactor: 컨벤션 적용

* refactor: 캐쉬 리팩터링 (#213)

* refactor : null value일때 cache 되는 것을 방지

* refactor : 패키지 변경

* refactor: 불필요한 메서드 제거

* fix: LiquorCtrRedisRepository NPE 해결

* refactor: LiquorSearchCondition 널 오브젝트 없애고 오버로드

* refactor: 기존 LiquorCtr 로직으로 변경

* Update src/main/java/com/woowacamp/soolsool/core/liquor/repository/LiquorQueryDslRepository.java

Co-authored-by: Jeonggyu Choi <[email protected]>

* refactor: 첫페이지 리팩터링

* refactor: Dto에서 entity, Page  인자 변경

---------

Co-authored-by: Jeonggyu Choi <[email protected]>

* refactor: LiquorCtr 반영 방식 리팩토링 (#219)

* refactor: LiquorCtr 반영 방식 리팩토링

* refactor: 사용하지 않는 메서드 제거

* refactor: 중복 코드 줄이기

* docs: 고민은 내일의 내가 한다

* refactor: RedisLiquorCtr toEntity 추가, LiquorCtr getCtr 로직 재사용

* refactor: LiquorCtr 부생성자 추가 및 적용

* fix: 실패 테스트 수정

* fix: Redis 테스트 환경 수정

* docs: 연관 상품 API 분리 todo 추가

* refactor: 불필요한 테스트 의존성 제거

* refactor: 피드백 반영

* fix: Redis 로직을 포함하는 테스트에서 메서드 전후로 Redis를 초기화하는 로직 추가

* refactor: 컨벤션 정리 및 readOnly 설정

* refactor: 클릭수, 노출수 반영 쿼리를 네이티브 쿼리로 수정

---------

Co-authored-by: whatasame <[email protected]>

* fix: git 충돌 해결

* fix: 불필요한 annotation 삭제

* refactor: 여러 개의 RLock을 MultiLock으로 관리 (#226)

* refactor: 여러 개의 RLock을 MultiLock으로 관리

* style: 주석 삭제

* feat: 첫 페이지 캐싱을 redis 로 변경 (#214)

* refactor : null value일때 cache 되는 것을 방지

* refactor : 패키지 변경

* refactor: 불필요한 메서드 제거

* fix: LiquorCtrRedisRepository NPE 해결

* feat: redis 의존성 추가

* feat: redis, caffeine Cache 설정 multi로 옮기기

* refactor: 카테고리는 caffeine으로 명시

* refactor: 첫 페이지는 redis cache로 명시

* refactor: expireSeconds 60초로 설정

* refactor: 기타 카테고리 또한 caffeineCache 명시

* test: test Config 설정

* fix: test Config 넣기

* fix: testConfiguration 설정

* refactor : printStackTrace 지우기

* refactor : redisTemplate 을 지우기

* liquorElementResponse 변경 완료

* Update src/main/java/com/woowacamp/soolsool/global/infra/RedisCacheType.java

Co-authored-by: Jeonggyu Choi <[email protected]>

* refactor: test cacheConfigurerSupport 삭제

* refactor: redis NPE 복구

* fix: test failed fix

* refactor: test config 삭제

* fix : test failed 수정

* refactor: 피드백 반영

* fix: test failed

* fix: test failed

* fix : test failed 해결

* Update src/main/java/com/woowacamp/soolsool/global/config/MultipleCacheManagerConfig.java

Co-authored-by: hwihwi523 <[email protected]>

* Update src/test/java/com/woowacamp/soolsool/core/order/service/OrderServiceIntegrationTest.java

Co-authored-by: hwihwi523 <[email protected]>

* Update src/main/java/com/woowacamp/soolsool/core/liquor/dto/PageLiquorResponse.java

Co-authored-by: hwihwi523 <[email protected]>

---------

Co-authored-by: Jeonggyu Choi <[email protected]>
Co-authored-by: hwihwi523 <[email protected]>

* refactor: 상품 상세정보, 연관상품, 클릭수, 노출수 API 분리 (#233)

* refactor: 상품 상세정보 조회에서 연관 상품 조회 API 분리

* refactor: 상품 상세정보 및 목록 조회에서 클릭수, 노출수 증가 API 분리

* refactor: import 정리

* Revert "refactor: 상품 상세정보, 연관상품, 클릭수, 노출수 API 분리 (#233)" (#235)

This reverts commit f2c22a1.

---------

Co-authored-by: worldii <[email protected]>
Co-authored-by: Jeonggyu Choi <[email protected]>
Co-authored-by: hwihwi523 <[email protected]>
  • Loading branch information
4 people authored Sep 18, 2023
1 parent 1d4ee56 commit e4b913e
Show file tree
Hide file tree
Showing 18 changed files with 513 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.woowacamp.soolsool.core.statistics.code;

import static org.springframework.http.HttpStatus.OK;

import com.woowacamp.soolsool.global.common.ResultCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum StatisticsResultCode implements ResultCode {

STATISTIC_TOP5_SALE_PRICE(OK.value(), "S101", "누적 판매금액이 가장 많은 술 상품 목록 top5 정상 조회 되었습니다."),
STATISTIC_TOP5_SALE_QUANTITY(OK.value(), "S102", "누적 판매량이 가장 많은 술 상품 목록 top5 정상 조회 되었습니다."),
;

private final int status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.woowacamp.soolsool.core.statistics.controller;

import static com.woowacamp.soolsool.core.statistics.code.StatisticsResultCode.STATISTIC_TOP5_SALE_PRICE;
import static com.woowacamp.soolsool.core.statistics.code.StatisticsResultCode.STATISTIC_TOP5_SALE_QUANTITY;
import static org.springframework.http.HttpStatus.OK;

import com.woowacamp.soolsool.core.statistics.dto.response.LiquorSalePriceResponse;
import com.woowacamp.soolsool.core.statistics.dto.response.LiquorSaleQuantityResponse;
import com.woowacamp.soolsool.core.statistics.service.StatisticService;
import com.woowacamp.soolsool.global.aop.RequestLogging;
import com.woowacamp.soolsool.global.auth.dto.NoAuth;
import com.woowacamp.soolsool.global.common.ApiResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@RequestMapping("/statistic")
@RequiredArgsConstructor
public class StatisticController {

private final StatisticService statisticService;

@NoAuth
@RequestLogging
@GetMapping("/price")
public ResponseEntity<ApiResponse<List<LiquorSalePriceResponse>>> findTop5LiquorsBySalePrice() {
final List<LiquorSalePriceResponse> liquorSalePriceResponses
= statisticService.findTop5LiquorsBySalePrice();

return ResponseEntity.status(OK)
.body(ApiResponse.of(STATISTIC_TOP5_SALE_PRICE, liquorSalePriceResponses));
}

@NoAuth
@RequestLogging
@GetMapping("/quantity")
public ResponseEntity<ApiResponse<List<LiquorSaleQuantityResponse>>> findTop5LiquorsBySaleQuantity() {
final List<LiquorSaleQuantityResponse> liquorSaleQuantityResponses
= statisticService.findTop5LiquorsBySaleQuantity();

return ResponseEntity.status(OK)
.body(ApiResponse.of(STATISTIC_TOP5_SALE_QUANTITY, liquorSaleQuantityResponses));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
@Table(name = "statistics")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Statistics {
public class Statistic {

@EmbeddedId
private StatisticsId statisticsId;
private StatisticId statisticId;

@Column(name = "region")
@Convert(converter = RegionConverter.class)
Expand All @@ -56,7 +56,7 @@ public class Statistics {
private SalePrice salePrice;

@Builder
public Statistics(
public Statistic(
final Region region,
final BrewType brewType,
final Impression impression,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class StatisticsId implements Serializable {
public class StatisticId implements Serializable {

@Column(name = "year")
private int year;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.woowacamp.soolsool.core.statistics.domain;

public interface StatisticLiquor {

Long getLiquorId();

String getLiquorName();

String getLiquorBrand();

String getLiquorImageUrl();

Long getLiquorPrice();

Long getLiquorValue();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.woowacamp.soolsool.core.statistics.domain;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class StatisticLiquorImpl implements StatisticLiquor {

private final Long liquorId;
private final String liquorName;
private final String liquorBrand;
private final String liquorImageUrl;
private final Long liquorPrice;
private final Long liquorValue;

public static StatisticLiquorImpl from(final StatisticLiquor statisticLiquor) {
return new StatisticLiquorImpl(
statisticLiquor.getLiquorId(),
statisticLiquor.getLiquorName(),
statisticLiquor.getLiquorBrand(),
statisticLiquor.getLiquorImageUrl(),
statisticLiquor.getLiquorPrice(),
statisticLiquor.getLiquorValue()
);
}

@Override
public Long getLiquorId() {
return this.liquorId;
}

@Override
public String getLiquorName() {
return this.liquorName;
}

@Override
public String getLiquorBrand() {
return this.liquorBrand;
}

@Override
public String getLiquorImageUrl() {
return this.liquorImageUrl;
}

@Override
public Long getLiquorPrice() {
return this.liquorPrice;
}

@Override
public Long getLiquorValue() {
return this.liquorValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.woowacamp.soolsool.core.statistics.domain;

import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class StatisticLiquors {

private final List<StatisticLiquorImpl> values;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.woowacamp.soolsool.core.statistics.dto.response;

import com.woowacamp.soolsool.core.statistics.domain.StatisticLiquor;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class LiquorSalePriceResponse {

private final Long id;
private final String name;
private final String brand;
private final String imageUrl;
private final Long price;
private final Long accumulatedSalePrice;

public static LiquorSalePriceResponse from(
@NonNull final StatisticLiquor statisticLiquor
) {
return new LiquorSalePriceResponse(
statisticLiquor.getLiquorId(),
statisticLiquor.getLiquorName(),
statisticLiquor.getLiquorBrand(),
statisticLiquor.getLiquorImageUrl(),
statisticLiquor.getLiquorPrice(),
statisticLiquor.getLiquorValue()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.woowacamp.soolsool.core.statistics.dto.response;

import com.woowacamp.soolsool.core.statistics.domain.StatisticLiquor;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class LiquorSaleQuantityResponse {

private final Long id;
private final String name;
private final String brand;
private final String imageUrl;
private final Long price;
private final Long accumulatedSaleQuantity;

public static LiquorSaleQuantityResponse from(
@NonNull final StatisticLiquor statisticLiquor
) {
return new LiquorSaleQuantityResponse(
statisticLiquor.getLiquorId(),
statisticLiquor.getLiquorName(),
statisticLiquor.getLiquorBrand(),
statisticLiquor.getLiquorImageUrl(),
statisticLiquor.getLiquorPrice(),
statisticLiquor.getLiquorValue()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.woowacamp.soolsool.core.statistics.repository;
package com.woowacamp.soolsool.core.statistics.infra;

import com.woowacamp.soolsool.core.statistics.domain.Statistics;
import com.woowacamp.soolsool.core.statistics.domain.StatisticsId;
import com.woowacamp.soolsool.core.statistics.domain.Statistic;
import com.woowacamp.soolsool.core.statistics.domain.StatisticId;
import com.woowacamp.soolsool.core.statistics.domain.StatisticLiquor;
import java.time.LocalDate;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface StatisticsRepository extends JpaRepository<Statistics, StatisticsId> {
public interface StatisticJpaRepository extends JpaRepository<Statistic, StatisticId> {

@Modifying
@Query(value =
Expand Down Expand Up @@ -57,4 +59,50 @@ void updateStatisticsSales(
"ON DUPLICATE KEY UPDATE impression = (lc.impression - s.sum_impression), " +
" click = (lc.click - s.sum_click)", nativeQuery = true)
void updateStatisticsCtr(final LocalDate date);

@Query(value = "SELECT l.id as liquorId, "
+ " l.name as liquorName, "
+ " l.brand as liquorBrand, "
+ " l.image_url as liquorImageUrl, "
+ " l.price as liquorPrice, "
+ " s.liquorValue as liquorValue "
+ "FROM ( "
+ " SELECT liquor_id, SUM(sale_price) AS liquorValue "
+ " FROM statistics "
+ " GROUP BY liquor_id "
+ " ORDER BY SUM(sale_price) DESC "
+ " LIMIT 5 "
+ ") s "
+ "JOIN liquors l ON s.liquor_id = l.id ", nativeQuery = true)
List<StatisticLiquor> findTop5LiquorsAndSalePrice();

@Query(value = "SELECT l.id as liquorId, "
+ " l.name as liquorName, "
+ " l.brand as liquorBrand, "
+ " l.image_url as liquorImageUrl, "
+ " l.price as liquorPrice, "
+ " s.liquorValue as liquorValue "
+ "FROM ( "
+ " SELECT liquor_id, SUM(sale_quantity) AS liquorValue "
+ " FROM statistics "
+ " GROUP BY liquor_id "
+ " ORDER BY SUM(sale_quantity) DESC "
+ " LIMIT 5 "
+ ") s "
+ "JOIN liquors l ON s.liquor_id = l.id ", nativeQuery = true)
List<StatisticLiquor> findTop5LiquorsAndSaleQuantity();

@Query(value = "select liquor_id as liquorId, sum(sale_price) as liquorValue "
+ "from statistics "
+ "group by liquor_id "
+ "order by sum(sale_price) desc "
+ "limit 5", nativeQuery = true)
List<StatisticLiquor> findTop5LiquorIdAndSalePrice();

@Query(value = "select liquor_id as liquorId, sum(sale_quantity) as liquorValue "
+ "from statistics "
+ "group by liquor_id "
+ "order by sum(sale_quantity) desc "
+ "limit 5", nativeQuery = true)
List<StatisticLiquor> findTop5LiquorIdAndSaleQuantity();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.woowacamp.soolsool.core.statistics.infra;

import com.woowacamp.soolsool.core.statistics.domain.StatisticLiquors;
import org.springframework.stereotype.Component;

@Component
public interface StatisticRedis {

StatisticLiquors findTop5StatisticLiquorsBySalePrice();

StatisticLiquors saveTop5StatisticLiquorsBySalePrice(
final StatisticLiquors statisticLiquors);

StatisticLiquors findTop5StatisticLiquorsBySaleQuantity();

StatisticLiquors saveTop5StatisticLiquorsBySaleQuantity(
final StatisticLiquors statisticLiquors);
}
Loading

0 comments on commit e4b913e

Please sign in to comment.