Skip to content

Commit

Permalink
Merge pull request #4 from Footprints-Plan/aurora-db
Browse files Browse the repository at this point in the history
[FP-58] Feat: 랭킹 기능 구현
  • Loading branch information
tjdgns8439 authored Aug 23, 2024
2 parents fc3c441 + fe2c5a8 commit 4ad898c
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 10 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
runtimeOnly 'com.mysql:mysql-connector-j'

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}

tasks.named('test') {
Expand Down
2 changes: 1 addition & 1 deletion config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.footprints.api.config.redis;

public abstract class BaseRedisRepository {
protected Class<?> classInstance;

abstract protected void init();
protected String generateGlobalKey(String localKey) {
return classInstance.getSimpleName().substring(0,classInstance.getSimpleName().length()-14) + "-" + localKey;
}
}
60 changes: 60 additions & 0 deletions src/main/java/com/footprints/api/config/redis/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.footprints.api.config.redis;


import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
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.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

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

@Value("${spring.data.redis.database}")
private int database;

@Value("${spring.data.redis.port}")
private int port;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(host, port);
connectionFactory.setDatabase(database);
return connectionFactory;
}

@Bean
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
ObjectMapper objectMapper = new ObjectMapper()
.findAndRegisterModules()
.enable(SerializationFeature.INDENT_OUTPUT) // 들여쓰기를 활성화
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // 날짜를 timestamp 변환하지 않도록 함
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
true) // 데이터가 불일치하는 상황이면 예외를 발생시킴
.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL,
"@class") // final이 아닌 타입도 저장할 수 있음, 객체의 클래스 정보를 저장
.registerModules(new JavaTimeModule()); // Java8의 날짜와 시간을 사용하기 위한 모듈을 등록
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(
objectMapper);
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
return redisTemplate;
}


}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.footprints.api.domain.items.controller;

import com.footprints.api.domain.items.dto.ItemResponseDto.ItemDetailInfo;
import com.footprints.api.domain.items.dto.ItemResponseDto.ItemRankingDto;
import com.footprints.api.domain.items.service.ItemService;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -37,8 +38,8 @@ public ResponseEntity<List<ItemDetailInfo>> getItemByName(@RequestParam String
}

@GetMapping("/rank")
public ResponseEntity<?> getItemRanking() {
return ResponseEntity.ok("");
public ResponseEntity<List<ItemRankingDto>> getItemRanking() {
return ResponseEntity.ok(itemService.getItemRanking());
}

@GetMapping("/category/{id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.cache.spi.support.AbstractReadWriteAccess.Item;





public class ItemResponseDto {
Expand Down Expand Up @@ -37,6 +33,29 @@ public static ItemDetailInfo toDto(Items entity) {
}
}

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class ItemRankingDto {
private Long id;
private String category;
private String name;
private Long price;
private Long salePrice;
private String imageUrl;
private Long score;
public static ItemRankingDto toDto(Items entity, Long score) {
return ItemRankingDto.builder()
.category(entity.getCategory().getCategoryName())
.name(entity.getName())
.price(entity.getPrice())
.salePrice(entity.getPrice())
.imageUrl(entity.getImageUrl())
.build();
}
}


}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.footprints.api.domain.items.repository;

import com.footprints.api.config.redis.BaseRedisRepository;
import jakarta.annotation.PostConstruct;
import java.io.Serializable;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class RedisItemRepository extends BaseRedisRepository implements Serializable {
private final RedisTemplate<String, String> redisTemplate;

public static final String RANKING = "item_rankings"; // 채팅룸에 입장한 클라이언트의 sessionId와 채팅룸 id를 맵핑한 정보 저장
private ZSetOperations<String, String> zSetOperations;

@PostConstruct
protected void init() {
classInstance = RedisItemRepository.class;
zSetOperations = redisTemplate.opsForZSet();
}

public List<TypedTuple<String>> getRankings(long start, long end) {
return zSetOperations.rangeWithScores(RANKING, start, end).stream()
.sorted(Comparator.comparingDouble(TypedTuple::getScore)) // Sort by score if needed
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import com.footprints.api.domain.category.entity.Category;
import com.footprints.api.domain.category.repository.CategoryRepository;
import com.footprints.api.domain.items.dto.ItemResponseDto.ItemDetailInfo;
import com.footprints.api.domain.items.dto.ItemResponseDto.ItemRankingDto;
import com.footprints.api.domain.items.entity.Items;
import com.footprints.api.domain.items.repository.ItemRepository;
import com.footprints.api.domain.items.repository.RedisItemRepository;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -17,6 +21,7 @@
public class ItemService {
private final ItemRepository itemRepository;
private final CategoryRepository categoryRepository;
private final RedisItemRepository redisItemRepository;

/**
* 전체 조회
Expand Down Expand Up @@ -62,7 +67,20 @@ public List<ItemDetailInfo> getItemByCategory(Long id){
/**
* 랭킹 조회 -> 레디스 설정 이후
*/
public ResponseEntity<?> getItemRanking() {
return ResponseEntity.ok("");
public List<ItemRankingDto> getItemRanking() {
List<TypedTuple<String>> redisRankings = redisItemRepository.getRankings(0,-1);

return redisRankings.stream()
.map(tuple -> {
String itemId = tuple.getValue();
Double score = tuple.getScore();

assert itemId != null;
Items item = itemRepository.findById(Long.parseLong(itemId)).orElseThrow();

assert score != null;
return ItemRankingDto.toDto(item, score.longValue());
})
.collect(Collectors.toList());
}
}

0 comments on commit 4ad898c

Please sign in to comment.