Skip to content

Commit 5288921

Browse files
authored
캐싱 적용 및 중복 로직 제거 (#35)
* [Fix]Test 코드 수정 * [Refactor]CafeteriaServiceV2 단일 책임 원칙 적용하여 클래스 분리 * Update Java CI-CD.yml dependency submission code removed * [Refactor]CampusServiceV2 클래스 분리 * [Refactor]DietServiceV2 서비스 클래스 분리 * [fix]Cafeteria Cacheable 주석처리 * [Refactor]캐시 적용 및 중복로직 최적화
1 parent b7c72f4 commit 5288921

File tree

10 files changed

+100
-78
lines changed

10 files changed

+100
-78
lines changed

src/main/java/com/example/Jinus/config/RedisCacheManager.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,37 +21,53 @@ public class RedisCacheManager {
2121
public CacheManager contentCacheManager(RedisConnectionFactory cf) {
2222
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
2323

24-
// 1. 식당 리스트 캐시 (불변 데이터, 7일 유지)
24+
// 1. 식당 리스트 캐시 (불변 데이터, 30일 유지)
2525
cacheConfigurations.put("cafeteriaList",
2626
RedisCacheConfiguration.defaultCacheConfig()
2727
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
2828
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
29-
.entryTtl(Duration.ofDays(7)) // 7일 유지
29+
.entryTtl(Duration.ofDays(30))
3030
.disableCachingNullValues()); // null 캐싱 방지
3131

3232

3333
// 2. 식단 데이터 캐시 (하루 단위로 갱신)
34-
cacheConfigurations.put("dietList",
34+
// cacheConfigurations.put("dietList",
35+
// RedisCacheConfiguration.defaultCacheConfig()
36+
// .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
37+
// .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
38+
// .entryTtl(Duration.ofHours(12))
39+
// .disableCachingNullValues());
40+
41+
// 3. 캠퍼스 이름 캐시 (불변 데이터, 30일 유지)
42+
cacheConfigurations.put("campusName",
3543
RedisCacheConfiguration.defaultCacheConfig()
3644
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
3745
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
38-
.entryTtl(Duration.ofHours(12)) // 12시간 유지
39-
.disableCachingNullValues());
46+
.entryTtl(Duration.ofDays(30))
47+
.disableCachingNullValues()); // null 캐싱 방지
4048

41-
// 3. 캠퍼스 이름별 캠퍼스 id 캐시 (불변 데이터, 7일 유지)
42-
cacheConfigurations.put("campusName",
49+
// 3. 식당 id 캐시 (불변 데이터, 30일 유지)
50+
cacheConfigurations.put("cafeteriaId",
4351
RedisCacheConfiguration.defaultCacheConfig()
4452
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
4553
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
46-
.entryTtl(Duration.ofDays(7)) // 7일 유지
54+
.entryTtl(Duration.ofDays(30))
4755
.disableCachingNullValues()); // null 캐싱 방지
4856

49-
// 3. 식당별 식당 id 캐시 (불변 데이터, 7일 유지)
50-
cacheConfigurations.put("cafeteriaId",
57+
// 4. 캠퍼스 id 캐시 (불변 데이터, 30일 유지)
58+
cacheConfigurations.put("campusId",
5159
RedisCacheConfiguration.defaultCacheConfig()
5260
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
5361
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
54-
.entryTtl(Duration.ofDays(7)) // 7일 유지
62+
.entryTtl(Duration.ofDays(30))
63+
.disableCachingNullValues()); // null 캐싱 방지
64+
65+
// 5. 식당 url 캐시 (불변 데이터, 30일 유지)
66+
cacheConfigurations.put("cafeteriaUrl",
67+
RedisCacheConfiguration.defaultCacheConfig()
68+
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // Key Serializer
69+
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) // Value Serializer
70+
.entryTtl(Duration.ofDays(30))
5571
.disableCachingNullValues()); // null 캐싱 방지
5672

5773

@@ -60,4 +76,5 @@ public CacheManager contentCacheManager(RedisConnectionFactory cf) {
6076
.withInitialCacheConfigurations(cacheConfigurations) // 캐시별 설정 적용
6177
.build();
6278
}
79+
6380
}

src/main/java/com/example/Jinus/config/RestTemplateConfig.java

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
import com.example.Jinus.dto.request.RequestDto;
44
import com.example.Jinus.service.v2.cafeteria.DietServiceV2;
5-
import com.fasterxml.jackson.databind.ObjectMapper;
65
import lombok.RequiredArgsConstructor;
7-
import org.springframework.beans.factory.annotation.Autowired;
86
import org.springframework.web.bind.annotation.PostMapping;
97
import org.springframework.web.bind.annotation.RequestBody;
108
import org.springframework.web.bind.annotation.RequestMapping;
@@ -16,9 +14,6 @@
1614
public class DietControllerV2 {
1715
private final DietServiceV2 dietServiceV2;
1816

19-
@Autowired
20-
private ObjectMapper objectMapper;
21-
2217
@PostMapping("/v2/dish")
2318
public String handleRequest(@RequestBody RequestDto requestDto) {
2419
return dietServiceV2.requestHandler(requestDto);

src/main/java/com/example/Jinus/service/v2/cafeteria/CacheServiceV2.java

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,65 @@
11
package com.example.Jinus.service.v2.cafeteria;
22

3+
import com.example.Jinus.config.RedisConfig;
34
import com.example.Jinus.dto.data.CafeteriaDto;
45
import com.example.Jinus.dto.data.DietDto;
56
import com.example.Jinus.dto.data.HandleRequestDto;
67
import com.example.Jinus.repository.v2.cafeteria.CafeteriaRepositoryV2;
78
import com.example.Jinus.repository.v2.cafeteria.DietRepositoryV2;
89
import lombok.RequiredArgsConstructor;
10+
import lombok.extern.slf4j.Slf4j;
911
import org.springframework.cache.annotation.Cacheable;
12+
import org.springframework.data.redis.core.RedisTemplate;
1013
import org.springframework.stereotype.Service;
1114

1215
import java.sql.Date;
16+
import java.time.Duration;
17+
import java.time.LocalDateTime;
1318
import java.util.List;
1419

1520
@Service
21+
@Slf4j
1622
@RequiredArgsConstructor
1723
public class CacheServiceV2 {
1824
private final DietRepositoryV2 dietRepositoryV2;
1925
private final CafeteriaRepositoryV2 cafeteriaRepositoryV2;
26+
private final RedisConfig redisConfig;
2027

21-
// @Cacheable(
22-
// value = "dietList",
23-
// key = "#parameters?.dietDate?.toString() + '::' + #parameters?.period + '::' + #cafeteriaId",
24-
// unless = "#result == null || #result.isEmpty()",
25-
// cacheManager = "contentCacheManager"
26-
// )
27-
// 식단 데이터 가져오기
2828
public List<DietDto> getDietList(HandleRequestDto parameters, int cafeteriaId) {
29-
// 오늘, 내일 문자열로 날짜 설정하기
30-
Date dietDate = parameters.getDietDate();
31-
// 식단 데이터 반환
32-
return dietRepositoryV2.findDietList(dietDate, parameters.getPeriod(), cafeteriaId);
29+
String key = parameters.getDietDate() + "::" + parameters.getPeriod() + "::" + cafeteriaId;
30+
31+
List<DietDto> cached = (List<DietDto>) redisConfig.redisTemplate().opsForValue().get(key);
32+
if (cached != null) return cached;
33+
34+
List<DietDto> result = dietRepositoryV2.findDietList(parameters.getDietDate(), parameters.getPeriod(), cafeteriaId);
35+
36+
if (result != null && !result.isEmpty()) {
37+
long ttlSeconds = calculateTtlUntilNextMidnight(parameters.getDietDate());
38+
redisConfig.redisTemplate().opsForValue().set(key, result, Duration.ofSeconds(ttlSeconds));
39+
}
40+
41+
return result;
42+
}
43+
44+
// 식단 데이터 TTL 동적 생성 -> 조회 시간과 하루 뒤의 자정시간까지의 시간차이가 TTL 시간
45+
// 즉, 날짜가 바뀌면 만료되어야 함
46+
private long calculateTtlUntilNextMidnight(Date dietDate) {
47+
LocalDateTime expireAt = dietDate.toLocalDate().plusDays(1).atStartOfDay(); // dietDate + 1일 자정
48+
LocalDateTime now = LocalDateTime.now();
49+
50+
Duration duration = Duration.between(now, expireAt);
51+
long seconds = duration.getSeconds();
52+
53+
// 만약 이미 만료되었거나, 현재 시간이 더 크면 0 리턴 (저장 안 함)
54+
return seconds > 0 ? seconds : 0;
3355
}
3456

3557

3658
// Redis에서 조회 (없으면 DB에서 가져옴)
37-
// @Cacheable(value = "cafeteriaList", key = "#campusId", cacheManager = "contentCacheManager")
59+
@Cacheable(
60+
value = "cafeteriaList",
61+
key = "#p0",
62+
cacheManager = "contentCacheManager")
3863
public List<CafeteriaDto> getCafeteriaList(int campusId) {
3964
return cafeteriaRepositoryV2.findCafeteriaListByCampusId(campusId);
4065
}

src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaQueryServiceV2.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,29 @@
22

33
import com.example.Jinus.repository.v2.cafeteria.CafeteriaRepositoryV2;
44
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
56
import org.springframework.cache.annotation.Cacheable;
67
import org.springframework.stereotype.Service;
78

89
@Service
910
@RequiredArgsConstructor
11+
@Slf4j
1012
public class CafeteriaQueryServiceV2 {
1113
private final CafeteriaRepositoryV2 cafeteriaRepositoryV2;
1214

13-
// @Cacheable(value = "cafeteriaId", key = "#campusId + '::' + #cafeteriaName",
14-
// unless = "#result == -1",
15-
// cacheManager = "contentCacheManager")
15+
@Cacheable(
16+
value = "cafeteriaId",
17+
key = "#p0 + '::' + #p1",
18+
unless = "#result == -1",
19+
cacheManager = "contentCacheManager")
1620
public int getCafeteriaId(String cafeteriaName, int campusId) {
1721
return cafeteriaRepositoryV2.findCafeteriaId(cafeteriaName, campusId).orElse(-1);
1822
}
1923

24+
@Cacheable(
25+
value = "cafeteriaUrl",
26+
key = "#p0",
27+
cacheManager = "contentCacheManager")
2028
public String getImgUrl(int cafeteriaId) {
2129
return cafeteriaRepositoryV2.findImgUrlByCafeteriaId(cafeteriaId);
2230
}

src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@
33
import com.example.Jinus.entity.cafeteria.CampusEntity;
44
import com.example.Jinus.repository.v2.cafeteria.CampusRepositoryV2;
55
import lombok.RequiredArgsConstructor;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.cache.annotation.Cacheable;
68
import org.springframework.stereotype.Service;
79

810
import java.util.List;
911

1012
@Service
1113
@RequiredArgsConstructor
14+
@Slf4j
1215
public class CampusServiceV2 {
1316
private final CampusRepositoryV2 campusRepositoryV2;
1417

18+
@Cacheable(
19+
value = "campusId",
20+
key = "#p0",
21+
cacheManager = "contentCacheManager")
1522
// 사용자의 campusId 받아 캠퍼스 이름 찾기
1623
public String getUserCampusName(int campusId) {
1724
return campusRepositoryV2.findCampusNameByCampusId(campusId);
@@ -22,7 +29,10 @@ public List<CampusEntity> getCampusList() {
2229
return campusRepositoryV2.findCampusList();
2330
}
2431

25-
// @Cacheable(value = "campusName", key = "#campusName", cacheManager = "contentCacheManager")
32+
@Cacheable(
33+
value = "campusName",
34+
key = "#p0",
35+
cacheManager = "contentCacheManager")
2636
// 캠퍼스 이름으로 id 찾기
2737
public int getCampusId(String campusName) {
2838
return campusRepositoryV2.findCampusIdByName(campusName);

src/main/java/com/example/Jinus/service/v2/cafeteria/DietParameterServiceV2.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.example.Jinus.dto.request.RequestDto;
66
import com.example.Jinus.service.v2.userInfo.UserServiceV2;
77
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
89
import org.springframework.stereotype.Service;
910

1011
import java.sql.Date;
@@ -14,6 +15,7 @@
1415

1516
@Service
1617
@RequiredArgsConstructor
18+
@Slf4j
1719
public class DietParameterServiceV2 {
1820

1921
private final UserServiceV2 userServiceV2;

src/main/java/com/example/Jinus/service/v2/cafeteria/DietQueryServiceV2.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.example.Jinus.dto.data.HandleRequestDto;
55
import com.example.Jinus.repository.v2.cafeteria.DietRepositoryV2;
66
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
78
import org.springframework.stereotype.Service;
89
import org.springframework.util.LinkedMultiValueMap;
910
import org.springframework.util.MultiValueMap;
@@ -15,36 +16,28 @@
1516

1617
@Service
1718
@RequiredArgsConstructor
19+
@Slf4j
1820
public class DietQueryServiceV2 {
1921

2022
private final CacheServiceV2 cacheServiceV2;
2123
private final DietRepositoryV2 dietRepositoryV2;
2224

2325
// 메뉴 존재 여부에 따른 반환값 처리 로직
2426
public String getDietResponse(HandleRequestDto parameters, int cafeteriaId) {
27+
// 메뉴 가져오기
28+
List<DietDto> dietDtos = cacheServiceV2.getDietList(parameters, cafeteriaId);
2529
// 메뉴 존재하는 경우
26-
if (checkThereIsDiet(parameters, cafeteriaId) != -1) {
30+
if (!dietDtos.isEmpty()) {
2731
// 메뉴 찾기
28-
MultiValueMap<String, String> dietList = getDiets(parameters, cafeteriaId);
32+
MultiValueMap<String, String> dietList = getDiets(dietDtos);
2933
return processDietList(dietList).toString();
3034
}
3135
return "\n메뉴가 존재하지 않습니다."; // 메뉴가 없는 경우
3236
}
3337

3438

35-
// 식당 메뉴 존재여부 확인
36-
private int checkThereIsDiet(HandleRequestDto parameters, int cafeteriaId) {
37-
// 오늘, 내일 문자열로 날짜 설정하기
38-
Date dietDate = parameters.getDietDate();
39-
List<DietDto> dietDtos =
40-
dietRepositoryV2.findDietList(dietDate, parameters.getPeriod(), cafeteriaId);
41-
return (!dietDtos.isEmpty()) ? 1 : -1;
42-
}
43-
44-
4539
// 카테고리별 메뉴 리스트 생성하기
46-
private MultiValueMap<String, String> getDiets(HandleRequestDto parameters, int cafeteriaId) {
47-
List<DietDto> dietDtos = cacheServiceV2.getDietList(parameters, cafeteriaId);
40+
private MultiValueMap<String, String> getDiets(List<DietDto> dietDtos) {
4841
MultiValueMap<String, String> dietList = new LinkedMultiValueMap<>(); // 중복 키 허용(값을 리스트로 반환)
4942

5043
for (DietDto o : dietDtos) {

src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,18 @@
22

33
import com.example.Jinus.dto.data.HandleRequestDto;
44
import com.example.Jinus.dto.request.RequestDto;
5-
import com.example.Jinus.repository.v2.cafeteria.DietRepositoryV2;
65
import com.example.Jinus.utility.DateUtils;
76
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
88
import org.springframework.stereotype.Service;
9-
import org.springframework.util.MultiValueMap;
109

1110
import java.sql.Date;
1211
import java.time.LocalDateTime;
1312
import java.time.LocalTime;
1413
import java.time.ZoneId;
15-
import java.util.Set;
16-
import java.util.TreeSet;
1714

1815
@Service
16+
@Slf4j
1917
@RequiredArgsConstructor
2018
public class DietServiceV2 {
2119

src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.example.Jinus.repository.v2.userInfo.UserRepositoryV2;
44
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
56
import org.springframework.data.redis.core.RedisTemplate;
67
import org.springframework.stereotype.Service;
78

@@ -11,6 +12,7 @@
1112

1213
@Service
1314
@RequiredArgsConstructor
15+
@Slf4j
1416
public class UserServiceV2 {
1517

1618
private final UserRepositoryV2 userRepositoryV2;

0 commit comments

Comments
 (0)