Skip to content

Commit

Permalink
Merge pull request #34 from Orange-Co/feature/search
Browse files Browse the repository at this point in the history
Feature/search: 최근 본 상품 저장
  • Loading branch information
Kang1221 authored Jul 20, 2024
2 parents d453b38 + d94d5ab commit 7b32271
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public ApiResponse<?> home() {
@GetMapping( "/product/{id}")
public ApiResponse<?> homeDetail(@RequestHeader("devicetoken") String devicetoken,
@PathVariable String id) {
log.info("devicetoken: {}", devicetoken);
return homeService.getProductDetail(id);
return homeService.getProductDetail(devicetoken, id);
}
}
17 changes: 9 additions & 8 deletions src/main/java/co/orange/ddanzi/controller/SearchController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
import co.orange.ddanzi.global.common.response.ApiResponse;
import co.orange.ddanzi.service.SearchService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1/search")
public class SearchController {
private final SearchService searchService;

@GetMapping()
ApiResponse<?> searchKeyword(@RequestParam("keyword") String keyword) {
return searchService.searchKeyword(keyword);
@GetMapping
ApiResponse<?> search(@RequestHeader(value = "devicetoken", required = false) String devicetoken,
@RequestParam(value = "keyword", required = false) String keyword) {
if (keyword == null)
return searchService.searchPage(devicetoken);
else
return searchService.searchKeyword(keyword);
}
}
}
9 changes: 8 additions & 1 deletion src/main/java/co/orange/ddanzi/domain/product/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public class Product {
// @OneToOne(fetch = FetchType.LAZY)
// @JoinColumn(name = "discount_id")
// private Discount discount; //할인 정보
@Column(name = "store")
private String store;

@Column(name = "title_first_5")
private String titleFirst5;

@Column(name = "title_last_5")
private String titleLast5;

@ColumnDefault("0")
@Column(name = "stock", nullable = false)
Expand All @@ -48,7 +56,6 @@ public class Product {
@Builder
public Product (String id, Long kakaoProductId, String name, String originName, Integer originPrice, String imgUrl, String infoUrl, Integer stock, Category leafCategory) {
this.id = id;
// this.discount = discount;
this.kakaoProductId = kakaoProductId;
this.name = name;
this.originName = originName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
@Builder
public class HomeDetailResponseDto {
private String name;
private String imgUrl;
private String category;
private Boolean isOptionExist;
private Boolean isImminent;
private Integer discountRate;
private Integer originPrice;
private Integer salePrice;
private Integer stockCount;
private String infoUrl;
private Integer interestCount;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package co.orange.ddanzi.dto.search;

import co.orange.ddanzi.dto.ProductInfo;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
public class SearchPageResponseDto {
private List<String> topSearchedList;
private List<ProductInfo> recentlyViewedList;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package co.orange.ddanzi.global.config.redis;
package co.orange.ddanzi.global.redis;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.StringRedisSerializer;


@EnableRedisRepositories
@Configuration
public class RedisConfig {

@Value("${spring.redis.host}")
private String redisHost;

Expand All @@ -25,12 +23,11 @@ public RedisConnectionFactory redisConnectionFactory() {
}

@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}

}
}
11 changes: 11 additions & 0 deletions src/main/java/co/orange/ddanzi/global/redis/RedisRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package co.orange.ddanzi.global.redis;

import java.util.Set;

public interface RedisRepository {
void saveDeviceToken(String deviceToken, String productId);

Set<String> getRecentProducts(String deviceToken);

void deleteDeviceToken(String deviceToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package co.orange.ddanzi.global.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.util.Set;


@Slf4j
@Repository
public class RedisRepositoryImpl implements RedisRepository {

private static final String DEVICE_PREFIX = "device:";

private final RedisTemplate<String, String> redisTemplate;

public RedisRepositoryImpl(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}

@Override
public void saveDeviceToken(String deviceToken, String productId) {
redisTemplate.opsForSet().add(DEVICE_PREFIX + deviceToken, productId);
}

@Override
public Set<String> getRecentProducts(String deviceToken) {
return redisTemplate.opsForSet().members(DEVICE_PREFIX + deviceToken);
}

@Override
public void deleteDeviceToken(String deviceToken) {
redisTemplate.delete(DEVICE_PREFIX + deviceToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Set;

public interface ProductRepository extends JpaRepository<Product, String> {

@Query("SELECT MAX(CAST(SUBSTRING(p.id, 4, 4) AS integer)) FROM Product p WHERE p.leafCategory = :leafCategory")
Integer findMaxSequenceNumberByCategory(@Param("leafCategory") Category leafCategory);


@Query("SELECT p FROM Product p WHERE p.kakaoProductId = :kakaoProductId")
Product findByKakaoProductId(Long kakaoProductId);

Expand All @@ -23,4 +23,5 @@ public interface ProductRepository extends JpaRepository<Product, String> {
@Query(value = "SELECT * FROM products p WHERE p.stock > 0 AND p.name LIKE %:keyword% ", nativeQuery = true)
List<Product> findAllByName(@Param("keyword") String keyword);

List<Product> findByIdIn(Set<String> productIds);
}
15 changes: 11 additions & 4 deletions src/main/java/co/orange/ddanzi/service/HomeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import co.orange.ddanzi.global.common.exception.Error;
import co.orange.ddanzi.global.common.response.ApiResponse;
import co.orange.ddanzi.global.common.response.Success;
import co.orange.ddanzi.global.redis.RedisRepository;
import co.orange.ddanzi.repository.*;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
Expand All @@ -27,6 +28,7 @@ public class HomeService {
private final OptionRepository optionRepository;
private final OptionDetailRepository optionDetailRepository;
private final InterestProductRepository interestProductRepository;
private final RedisRepository redisRepository;

@Transactional
public ApiResponse<?> getProductList(){
Expand All @@ -41,7 +43,7 @@ public ApiResponse<?> getProductList(){
}

@Transactional
public ApiResponse<?> getProductDetail(String productId){
public ApiResponse<?> getProductDetail(String devicetoken, String productId){
log.info("상품 조회 -> product_id: {}", productId);
Product product = productRepository.findById(productId).orElse(null);
if(product == null){
Expand All @@ -52,12 +54,11 @@ public ApiResponse<?> getProductDetail(String productId){
ApiResponse.onFailure(Error.CATEGORY_NOT_FOUND, null);
}
Category leafCategory = product.getLeafCategory();
log.info("카테고리 조회 성공 -> catgory_id: {}", leafCategory.getId());

log.info("카테고리 full path 조회");
String categoryFullPath = leafCategory.getFullPath();

log.info("상품 할인율 조회 -> product_id: {}",productId);
log.info("상품 할인율 조회");
Discount discount = discountRepository.findById(productId).orElse(null);
if(discount == null){
ApiResponse.onFailure(Error.DISCOUNT_INFO_NOT_FOUND, null);
Expand All @@ -71,13 +72,19 @@ public ApiResponse<?> getProductDetail(String productId){
log.info("해당 상품의 찜 개수 조회");
Integer interestCount = interestProductRepository.countByProductIdWithLimit(productId);


log.info("최근 본 상품 등록");
redisRepository.saveDeviceToken(devicetoken, productId);
log.info("최근 본 상품 등록 성공");
HomeDetailResponseDto responseDto = HomeDetailResponseDto.builder()
.name(product.getName())
.imgUrl(product.getImgUrl())
.category(categoryFullPath)
.isOptionExist(!optionList.isEmpty())
.isImminent(true)
.discountRate(discountRate)
.originPrice(product.getOriginPrice())
.salePrice(product.getOriginPrice() - discount.getDiscountPrice())
.infoUrl(product.getInfoUrl())
.stockCount(product.getStock())
.infoUrl(product.getInfoUrl())
.interestCount(interestCount)
Expand Down
21 changes: 20 additions & 1 deletion src/main/java/co/orange/ddanzi/service/SearchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,47 @@

import co.orange.ddanzi.domain.product.Product;
import co.orange.ddanzi.dto.ProductInfo;
import co.orange.ddanzi.dto.search.SearchPageResponseDto;
import co.orange.ddanzi.dto.search.SearchResultResponseDto;
import co.orange.ddanzi.global.common.response.ApiResponse;
import co.orange.ddanzi.global.common.response.Success;
import co.orange.ddanzi.global.redis.RedisRepository;
import co.orange.ddanzi.repository.InterestProductRepository;
import co.orange.ddanzi.repository.ProductRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
@RequiredArgsConstructor
@Service
public class SearchService {
private final HomeService homeService;
private final ProductRepository productRepository;
private final InterestProductRepository interestProductRepository;
private final RedisRepository redisRepository;

@Transactional
public ApiResponse<?> searchPage(String devicetoken) {
List<String> topSearchedList = List.of("예시1", "예시2", "예시3");
log.info("Searching page for devicetoken: {}", devicetoken);
Set<String> recentViewedProductIds = redisRepository.getRecentProducts(devicetoken);
List<Product> productList = productRepository.findByIdIn(recentViewedProductIds);
List<ProductInfo> productInfoList = homeService.setProductList(productList, interestProductRepository);
return ApiResponse.onSuccess(Success.GET_SEARCH_SCREEN_SUCCESS, SearchPageResponseDto.builder()
.topSearchedList(topSearchedList)
.recentlyViewedList(productInfoList)
.build());
}

@Transactional
public ApiResponse<?> searchKeyword(String keyword) {
List<String> topSearchedList = List.of("예시1", "예시2", "예시3");
log.info("Search for keyword: {}", keyword);
List<Product> productList = productRepository.findAllByName(keyword);
List<ProductInfo> productInfoList = homeService.setProductList(productList, interestProductRepository);
return ApiResponse.onSuccess(Success.GET_SEARCH_RESULTS_SUCCESS, SearchResultResponseDto.builder()
Expand Down

0 comments on commit 7b32271

Please sign in to comment.