Skip to content

Commit

Permalink
refactor: 상품 상세정보, 연관상품, 클릭수, 노출수 API 분리 (#236)
Browse files Browse the repository at this point in the history
* refactor: 상품 상세정보 조회에서 연관 상품 조회 API 분리

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

* refactor: import 정리

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

* style: 불필요 import 제거

* refactor: 테스트 코드 수정
  • Loading branch information
hwihwi523 authored Sep 20, 2023
1 parent df226e7 commit aebada2
Show file tree
Hide file tree
Showing 18 changed files with 285 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
@Getter
@RequiredArgsConstructor
public enum LiquorCtrResultCode implements ResultCode {

FIND_LQUOR_CTR_SUCCESS(OK.value(), "LC001", "술 클릭률 조회에 성공했습니다."),

FIND_LIQUOR_CTR_SUCCESS(OK.value(), "LC001", "술 클릭률 조회에 성공했습니다."),
INCREASE_IMPRESSION_SUCCESS(OK.value(), "LC002", "술 노출수 증가에 성공했습니다."),
INCREASE_CLICK_SUCCESS(OK.value(), "LC003", "술 클릭수 증가에 성공했습니다."),
;

private final int status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum LiquorResultCode implements ResultCode {
LIQUOR_LIST_FOUND(OK.value(), "L103", "술 목록이 정상적으로 검색되었습니다."),
LIQUOR_UPDATED(OK.value(), "L104", "술 상품이 정상적으로 수정되었습니다."),
LIQUOR_DELETED(NO_CONTENT.value(), "L105", "술 상품이 정상적으로 삭제되었습니다."),
LIQUOR_PURCHASED_TOGETHER_FOUND(OK.value(), "L106", "연관 상품 목록이 정상적으로 검색되었습니다."),
;

private final int status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorRegionType;
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorStatusType;
import com.woowacamp.soolsool.core.liquor.dto.LiquorDetailResponse;
import com.woowacamp.soolsool.core.liquor.dto.LiquorElementResponse;
import com.woowacamp.soolsool.core.liquor.dto.LiquorModifyRequest;
import com.woowacamp.soolsool.core.liquor.dto.LiquorSaveRequest;
import com.woowacamp.soolsool.core.liquor.dto.PageLiquorResponse;
Expand All @@ -19,6 +20,7 @@
import com.woowacamp.soolsool.global.auth.dto.Vendor;
import com.woowacamp.soolsool.global.common.ApiResponse;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
Expand Down Expand Up @@ -68,6 +70,19 @@ public ResponseEntity<ApiResponse<LiquorDetailResponse>> liquorDetail(
return ResponseEntity.ok(ApiResponse.of(LiquorResultCode.LIQUOR_DETAIL_FOUND, response));
}

@NoAuth
@RequestLogging
@GetMapping("/{liquorId}/related")
public ResponseEntity<ApiResponse<List<LiquorElementResponse>>> liquorPurchasedTogether(
@PathVariable final Long liquorId
) {
final List<LiquorElementResponse> response =
liquorService.liquorPurchasedTogether(liquorId);

return ResponseEntity.ok(
ApiResponse.of(LiquorResultCode.LIQUOR_PURCHASED_TOGETHER_FOUND, response));
}

@NoAuth
@RequestLogging
@GetMapping("/first")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.woowacamp.soolsool.core.liquor.controller;

import com.woowacamp.soolsool.core.liquor.code.LiquorCtrResultCode;
import com.woowacamp.soolsool.core.liquor.dto.response.LiquorCtrDetailResponse;
import com.woowacamp.soolsool.core.liquor.dto.liquorCtr.LiquorClickAddRequest;
import com.woowacamp.soolsool.core.liquor.dto.liquorCtr.LiquorCtrDetailResponse;
import com.woowacamp.soolsool.core.liquor.dto.liquorCtr.LiquorImpressionAddRequest;
import com.woowacamp.soolsool.core.liquor.service.LiquorCtrService;
import com.woowacamp.soolsool.global.aop.RequestLogging;
import com.woowacamp.soolsool.global.auth.dto.NoAuth;
import com.woowacamp.soolsool.global.common.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -27,8 +31,30 @@ public ResponseEntity<ApiResponse<LiquorCtrDetailResponse>> findLiquorCtr(
@RequestParam final Long liquorId
) {
return ResponseEntity.ok(
ApiResponse.of(LiquorCtrResultCode.FIND_LQUOR_CTR_SUCCESS,
ApiResponse.of(LiquorCtrResultCode.FIND_LIQUOR_CTR_SUCCESS,
new LiquorCtrDetailResponse(liquorCtrService.getLiquorCtrByLiquorId(liquorId)))
);
}

@NoAuth
@RequestLogging
@PatchMapping("/impressions")
public ResponseEntity<ApiResponse<Void>> increaseImpression(
@RequestBody final LiquorImpressionAddRequest request
) {
liquorCtrService.increaseImpression(request);

return ResponseEntity.ok(ApiResponse.from(LiquorCtrResultCode.INCREASE_IMPRESSION_SUCCESS));
}

@NoAuth
@RequestLogging
@PatchMapping("/clicks")
public ResponseEntity<ApiResponse<Void>> increaseClick(
@RequestBody final LiquorClickAddRequest request
) {
liquorCtrService.increaseClick(request);

return ResponseEntity.ok(ApiResponse.from(LiquorCtrResultCode.INCREASE_CLICK_SUCCESS));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.woowacamp.soolsool.core.liquor.dto;

import com.woowacamp.soolsool.core.liquor.domain.Liquor;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

Expand All @@ -18,13 +16,8 @@ public class LiquorDetailResponse {
private final Integer stock;
private final Double alcohol;
private final Integer volume;
private final List<LiquorElementResponse> relatedLiquors; // TODO: 연관 상품 API 분리

public static LiquorDetailResponse of(final Liquor liquor, final List<Liquor> relatedLiquors) {
final List<LiquorElementResponse> relatedLiquorResponses = relatedLiquors.stream()
.map(LiquorElementResponse::from)
.collect(Collectors.toList());

public static LiquorDetailResponse of(final Liquor liquor) {
return new LiquorDetailResponse(
liquor.getId(),
liquor.getName(),
Expand All @@ -33,8 +26,7 @@ public static LiquorDetailResponse of(final Liquor liquor, final List<Liquor> re
liquor.getImageUrl(),
liquor.getTotalStock(),
liquor.getAlcohol(),
liquor.getVolume(),
relatedLiquorResponses
liquor.getVolume()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.List;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;

@Getter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.woowacamp.soolsool.core.liquor.dto.liquorCtr;

import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;

@Getter
public class LiquorClickAddRequest {

private final Long liquorId;

@JsonCreator
public LiquorClickAddRequest(final Long liquorId) {
this.liquorId = liquorId;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.woowacamp.soolsool.core.liquor.dto.response;
package com.woowacamp.soolsool.core.liquor.dto.liquorCtr;

import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.woowacamp.soolsool.core.liquor.dto.liquorCtr;

import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.List;
import lombok.Getter;

@Getter
public class LiquorImpressionAddRequest {

private final List<Long> liquorIds;

@JsonCreator
public LiquorImpressionAddRequest(final List<Long> liquorIds) {
this.liquorIds = liquorIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.woowacamp.soolsool.core.liquor.domain.LiquorBrew;
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorBrewType;

import java.util.Optional;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.woowacamp.soolsool.core.liquor.domain.LiquorStatus;
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorStatusType;

import java.util.Optional;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.woowacamp.soolsool.core.liquor.service;

import com.woowacamp.soolsool.core.liquor.domain.LiquorCtr;
import com.woowacamp.soolsool.core.liquor.dto.liquorCtr.LiquorClickAddRequest;
import com.woowacamp.soolsool.core.liquor.dto.liquorCtr.LiquorImpressionAddRequest;
import com.woowacamp.soolsool.core.liquor.repository.LiquorCtrRepository;
import com.woowacamp.soolsool.core.liquor.repository.redisson.LiquorCtrRedisRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,6 +24,14 @@ public double getLiquorCtrByLiquorId(final Long liquorId) {
return liquorCtrRedisRepository.getCtr(liquorId);
}

public void increaseImpression(final LiquorImpressionAddRequest request) {
request.getLiquorIds().forEach(liquorCtrRedisRepository::increaseImpression);
}

public void increaseClick(final LiquorClickAddRequest request) {
liquorCtrRedisRepository.increaseClick(request.getLiquorId());
}

@Transactional
public void writeBackCtr(final LiquorCtr latestLiquorCtr) {
liquorCtrRepository.updateLiquorCtr(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorRegionType;
import com.woowacamp.soolsool.core.liquor.domain.vo.LiquorStatusType;
import com.woowacamp.soolsool.core.liquor.dto.LiquorDetailResponse;
import com.woowacamp.soolsool.core.liquor.dto.LiquorElementResponse;
import com.woowacamp.soolsool.core.liquor.dto.LiquorModifyRequest;
import com.woowacamp.soolsool.core.liquor.dto.LiquorSaveRequest;
import com.woowacamp.soolsool.core.liquor.dto.LiquorSearchCondition;
Expand All @@ -24,9 +25,9 @@
import com.woowacamp.soolsool.core.liquor.repository.LiquorRegionCache;
import com.woowacamp.soolsool.core.liquor.repository.LiquorRepository;
import com.woowacamp.soolsool.core.liquor.repository.LiquorStatusCache;
import com.woowacamp.soolsool.core.liquor.repository.redisson.LiquorCtrRedisRepository;
import com.woowacamp.soolsool.global.exception.SoolSoolException;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
Expand All @@ -49,8 +50,6 @@ public class LiquorService {
private final LiquorCtrRepository liquorCtrRepository;
private final LiquorQueryDslRepository liquorQueryDslRepository;

private final LiquorCtrRedisRepository liquorCtrRedisRepository;

@CacheEvict(value = "liquorsFirstPage")
@Transactional
public Long saveLiquor(final LiquorSaveRequest request) {
Expand All @@ -71,12 +70,17 @@ public LiquorDetailResponse liquorDetail(final Long liquorId) {
final Liquor liquor = liquorRepository.findById(liquorId)
.orElseThrow(() -> new SoolSoolException(NOT_LIQUOR_FOUND));

return LiquorDetailResponse.of(liquor);
}

@Transactional(readOnly = true)
public List<LiquorElementResponse> liquorPurchasedTogether(final Long liquorId) {
final List<Liquor> relatedLiquors = liquorRepository
.findLiquorsPurchasedTogether(liquorId, TOP_RANK_PAGEABLE);

liquorCtrRedisRepository.increaseClick(liquorId);

return LiquorDetailResponse.of(liquor, relatedLiquors);
return relatedLiquors.stream()
.map(LiquorElementResponse::from)
.collect(Collectors.toList());
}

@Transactional
Expand All @@ -95,26 +99,16 @@ public PageLiquorResponse liquorList(
brand
);

List<Liquor> liquors = liquorQueryDslRepository
final List<Liquor> liquors = liquorQueryDslRepository
.getList(liquorSearchCondition, pageable, cursorId);

liquors.stream()
.map(Liquor::getId)
.sorted()
.forEach(liquorCtrRedisRepository::increaseImpression);

return PageLiquorResponse.of(pageable, liquors);
}

@Transactional
public PageLiquorResponse getFirstPage(final Pageable pageable) {
final List<Liquor> liquors = liquorQueryDslRepository.getCachedList(pageable);

liquors.stream()
.map(Liquor::getId)
.sorted()
.forEach(liquorCtrRedisRepository::increaseImpression);

return PageLiquorResponse.of(pageable, liquors);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,13 @@ void liquorDetail() {
() -> assertThat(liquorDetailResponse.getImageUrl()).isEqualTo("/soju-url"),
() -> assertThat(liquorDetailResponse.getStock()).isZero(),
() -> assertThat(liquorDetailResponse.getAlcohol()).isEqualTo(12.0),
() -> assertThat(liquorDetailResponse.getVolume()).isEqualTo(300),
() -> assertThat(liquorDetailResponse.getRelatedLiquors()).isEmpty()
() -> assertThat(liquorDetailResponse.getVolume()).isEqualTo(300)
);
}

@Test
@DisplayName("술 상세정보를 연관된 상품과 함께 조회할 수 있다")
void liquorDetailWithRelatedLiquors() {
@DisplayName("특정 상품과 함께 많이 구매된 상품 목록을 조회할 수 있다")
void liquorPurchasedTogether() {
// given
String vendorAccessToken = RestAuthFixture.로그인_최민족_판매자();
Long 새로_Id = RestLiquorFixture.술_등록_새로_판매중(vendorAccessToken);
Expand All @@ -172,29 +171,20 @@ void liquorDetailWithRelatedLiquors() {
RestPayFixture.결제_성공(customerAccessToken, 주문서_Id);

// when
LiquorDetailResponse liquorDetailResponse = RestAssured
List<LiquorElementResponse> responses = RestAssured
.given().log().all()
.contentType(APPLICATION_JSON_VALUE)
.accept(APPLICATION_JSON_VALUE)
.when().get("/api/liquors/{liquorId}", 새로_Id)
.when().get("/api/liquors/{liquorId}/related", 새로_Id)
.then().log().all()
.extract().jsonPath().getObject("data", LiquorDetailResponse.class);
.extract().jsonPath().getList("data", LiquorElementResponse.class);

List<Long> relatedLiquorIds = liquorDetailResponse.getRelatedLiquors().stream()
List<Long> relatedLiquorIds = responses.stream()
.map(LiquorElementResponse::getId)
.collect(Collectors.toList());

// then
assertAll(
() -> assertThat(liquorDetailResponse.getName()).isEqualTo("새로"),
() -> assertThat(liquorDetailResponse.getPrice()).isEqualTo("3000"),
() -> assertThat(liquorDetailResponse.getBrand()).isEqualTo("롯데"),
() -> assertThat(liquorDetailResponse.getImageUrl()).isEqualTo("/soju-url"),
() -> assertThat(liquorDetailResponse.getStock()).isEqualTo(99),
() -> assertThat(liquorDetailResponse.getAlcohol()).isEqualTo(12.0),
() -> assertThat(liquorDetailResponse.getVolume()).isEqualTo(300),
() -> assertThat(relatedLiquorIds).containsExactlyInAnyOrder(얼음딸기주_Id)
);
assertThat(relatedLiquorIds).containsExactlyInAnyOrder(얼음딸기주_Id);
}

@Test
Expand Down
Loading

0 comments on commit aebada2

Please sign in to comment.