Skip to content

Commit 4f70b27

Browse files
committed
refactor: cluster/marker API를 geohash→dto 조회 방식으로 수정
1 parent 75d4c6c commit 4f70b27

File tree

7 files changed

+156
-244
lines changed

7 files changed

+156
-244
lines changed

src/main/java/com/example/log4u/domain/diary/service/DiaryGeohashService.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import com.example.log4u.domain.diary.entity.DiaryGeoHash;
99
import com.example.log4u.domain.diary.repository.DiaryGeoHashRepository;
10-
import com.example.log4u.domain.map.cache.dao.DiaryCacheDao;
10+
import com.example.log4u.domain.map.cache.dao.MarkerCacheDao;
1111

1212
import ch.hsr.geohash.GeoHash;
1313
import lombok.RequiredArgsConstructor;
@@ -19,7 +19,7 @@
1919
public class DiaryGeohashService {
2020

2121
private final DiaryGeoHashRepository diaryGeoHashRepository;
22-
private final DiaryCacheDao diaryCacheDao;
22+
private final MarkerCacheDao markerCacheDao;
2323

2424
@Transactional
2525
public void saveGeohash(Long diaryId, double lat, double lon) {
@@ -34,9 +34,7 @@ public void saveGeohash(Long diaryId, double lat, double lon) {
3434
@Transactional
3535
public void deleteGeohashAndCache(Long diaryId) {
3636
DiaryGeoHash geoHash = diaryGeoHashRepository.findByDiaryId(diaryId);
37-
diaryCacheDao.evictDiaryIdFromCache(geoHash.getGeohash(), diaryId);
38-
diaryCacheDao.evictDiaryFromCache(diaryId);
39-
37+
markerCacheDao.evict(geoHash.getGeohash());
4038
diaryGeoHashRepository.deleteById(diaryId);
4139
}
4240

src/main/java/com/example/log4u/domain/map/cache/CacheKeyGenerator.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@
22

33
public class CacheKeyGenerator {
44

5-
private static final String CLUSTER_CACHE_KEY_FORMAT = "cluster:geohash:%s:level:%d";
6-
private static final String DIARY_KEY_PREFIX = "marker:diary:";
7-
private static final String GEOHASH_ID_SET_PREFIX = "marker:ids:geohash:";
5+
private static final String CLUSTER_CACHE_KEY = "cluster:geohash:%s:level:%d";
6+
private static final String MARKER_CACHE_KEY = "marker:geohash:";
87

98
public static String clusterCacheKey(String geohash, int level) {
10-
return String.format(CLUSTER_CACHE_KEY_FORMAT, geohash, level);
9+
return String.format(CLUSTER_CACHE_KEY, geohash, level);
1110
}
1211

13-
public static String diaryKey(Long diaryId) {
14-
return DIARY_KEY_PREFIX + diaryId;
15-
}
16-
17-
public static String diaryIdSetKey(String geohash) {
18-
return GEOHASH_ID_SET_PREFIX + geohash;
12+
public static String markerCacheKey(String geohash) {
13+
return MARKER_CACHE_KEY + geohash;
1914
}
2015
}
21-

src/main/java/com/example/log4u/domain/map/cache/dao/ClusterCacheDao.java

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,69 @@
88
import org.springframework.stereotype.Component;
99

1010
import com.example.log4u.domain.map.cache.CacheKeyGenerator;
11+
import com.example.log4u.domain.map.cache.RedisTTLPolicy;
1112
import com.example.log4u.domain.map.dto.response.DiaryClusterResponseDto;
13+
import com.example.log4u.domain.map.exception.InvalidMapLevelException;
14+
import com.example.log4u.domain.map.repository.sido.SidoAreasDiaryCountRepository;
15+
import com.example.log4u.domain.map.repository.sido.SidoAreasRepository;
16+
import com.example.log4u.domain.map.repository.sigg.SiggAreasDiaryCountRepository;
17+
import com.example.log4u.domain.map.repository.sigg.SiggAreasRepository;
18+
import com.fasterxml.jackson.databind.ObjectMapper;
1219

1320
import lombok.RequiredArgsConstructor;
1421
import lombok.extern.slf4j.Slf4j;
1522

23+
import com.fasterxml.jackson.core.type.TypeReference;
24+
25+
1626
@Component
1727
@RequiredArgsConstructor
1828
@Slf4j
1929
public class ClusterCacheDao {
2030

21-
private final RedisTemplate<String, List<DiaryClusterResponseDto>> diaryClusterRedisTemplate;
31+
private final RedisTemplate<String, String> redisTemplate;
32+
private final ObjectMapper objectMapper;
33+
private final SidoAreasRepository sidoAreasRepository;
34+
private final SiggAreasRepository siggAreasRepository;
2235

23-
public Optional<List<DiaryClusterResponseDto>> getDiaryCluster(String geohash, int level) {
36+
public List<DiaryClusterResponseDto> load(String geohash, int level) {
37+
String key = CacheKeyGenerator.clusterCacheKey(geohash, level);
2438
try {
25-
String key = CacheKeyGenerator.clusterCacheKey(geohash, level);
26-
List<DiaryClusterResponseDto> cached = diaryClusterRedisTemplate.opsForValue().get(key);
27-
return Optional.ofNullable(cached);
39+
String value = redisTemplate.opsForValue().get(key);
40+
if (value == null){
41+
return null;
42+
}
43+
return objectMapper.readValue(value, new TypeReference<>() {
44+
});
2845
} catch (Exception e) {
29-
log.warn("클러스터 캐시 조회 실패 (geo={}, level={})", geohash, level, e);
30-
return Optional.empty();
46+
log.warn("[REDIS][CLUSTER][GET][ERR] key={}", key, e);
47+
throw new RuntimeException(e);
3148
}
3249
}
3350

34-
public void setDiaryCluster(String geohash, int level, List<DiaryClusterResponseDto> data, Duration ttl) {
51+
public List<DiaryClusterResponseDto> loadAndCache(String geohash, int level) {
52+
List<DiaryClusterResponseDto> clusters = loadClustersFromDb(geohash, level);
53+
cache(clusters,geohash, level);
54+
return clusters;
55+
}
56+
57+
private List<DiaryClusterResponseDto> loadClustersFromDb(String geohash, int level) {
58+
return switch (level) {
59+
case 1 -> sidoAreasRepository.findByGeohashPrefix(geohash);
60+
case 2 -> siggAreasRepository.findByGeohashPrefix(geohash);
61+
default -> throw new InvalidMapLevelException();
62+
};
63+
}
64+
65+
private void cache(List<DiaryClusterResponseDto> clusters, String geohash, int level) {
66+
String key = CacheKeyGenerator.clusterCacheKey(geohash, level);
67+
3568
try {
36-
String key = CacheKeyGenerator.clusterCacheKey(geohash, level);
37-
diaryClusterRedisTemplate.opsForValue().set(key, data, ttl);
69+
String json = objectMapper.writeValueAsString(clusters);
70+
redisTemplate.opsForValue().set(key, json, RedisTTLPolicy.CLUSTER_TTL);
3871
} catch (Exception e) {
39-
log.warn("클러스터 캐시 저장 실패 (geo={}, level={})", geohash, level, e);
72+
log.warn("클러스터 캐시 저장 실패 (geo={}, level={})", key, clusters.size(), e);
73+
throw new RuntimeException(e);
4074
}
4175
}
4276
}

src/main/java/com/example/log4u/domain/map/cache/dao/DiaryCacheDao.java

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.example.log4u.domain.map.cache.dao;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
import org.springframework.data.redis.core.RedisTemplate;
7+
import org.springframework.stereotype.Component;
8+
9+
import com.example.log4u.domain.diary.entity.Diary;
10+
import com.example.log4u.domain.diary.repository.DiaryGeoHashRepository;
11+
import com.example.log4u.domain.diary.repository.DiaryRepository;
12+
import com.example.log4u.domain.map.cache.CacheKeyGenerator;
13+
import com.example.log4u.domain.map.cache.RedisTTLPolicy;
14+
import com.example.log4u.domain.map.dto.response.DiaryMarkerResponseDto;
15+
import com.fasterxml.jackson.core.type.TypeReference;
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
18+
import lombok.RequiredArgsConstructor;
19+
import lombok.extern.slf4j.Slf4j;
20+
21+
@Component
22+
@RequiredArgsConstructor
23+
@Slf4j
24+
public class MarkerCacheDao {
25+
26+
private final RedisTemplate<String, String> redisTemplate;
27+
private final ObjectMapper objectMapper;
28+
29+
private final DiaryRepository diaryRepository;
30+
private final DiaryGeoHashRepository diaryGeoHashRepository;
31+
32+
public List<DiaryMarkerResponseDto> load(String geohash) {
33+
String key = CacheKeyGenerator.markerCacheKey(geohash);
34+
try {
35+
String value = redisTemplate.opsForValue().get(key);
36+
if (value == null) {
37+
return null;
38+
}
39+
return objectMapper.readValue(value, new TypeReference<>() {
40+
});
41+
} catch (Exception e) {
42+
log.warn("[REDIS][GET][ERR] key={}", key, e);
43+
throw new RuntimeException(e);
44+
}
45+
}
46+
47+
public List<DiaryMarkerResponseDto> loadAndCache(String geohash) {
48+
List<Long> diaryIds = diaryGeoHashRepository.findDiaryIdByGeohash(geohash);
49+
if (diaryIds.isEmpty()) {
50+
cache(Collections.emptyList(), geohash);
51+
return Collections.emptyList();
52+
}
53+
List<Diary> diaries = diaryRepository.findAllById(diaryIds);
54+
List<DiaryMarkerResponseDto> markers = diaries.stream()
55+
.map(DiaryMarkerResponseDto::of)
56+
.toList();
57+
cache(markers, geohash);
58+
return markers;
59+
}
60+
61+
private void cache(List<DiaryMarkerResponseDto> markers, String geohash) {
62+
String key = CacheKeyGenerator.markerCacheKey(geohash);
63+
try {
64+
String json = objectMapper.writeValueAsString(markers);
65+
redisTemplate.opsForValue().set(key, json, RedisTTLPolicy.DIARY_TTL);
66+
} catch (Exception e) {
67+
log.warn("[REDIS][SET][ERR] key={} count={}", key, markers.size(), e);
68+
throw new RuntimeException(e);
69+
}
70+
}
71+
72+
public void evict(String geohash) {
73+
String key = CacheKeyGenerator.markerCacheKey(geohash);
74+
try {
75+
redisTemplate.delete(key);
76+
} catch (Exception e) {
77+
throw new RuntimeException(e);
78+
}
79+
}
80+
}

src/main/java/com/example/log4u/domain/map/controller/MapController.java

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,12 @@
22

33
import java.util.List;
44

5-
import org.springframework.beans.factory.annotation.Value;
6-
import org.springframework.http.HttpEntity;
7-
import org.springframework.http.HttpHeaders;
8-
import org.springframework.http.HttpMethod;
95
import org.springframework.http.ResponseEntity;
10-
import org.springframework.security.core.annotation.AuthenticationPrincipal;
116
import org.springframework.web.bind.annotation.GetMapping;
12-
import org.springframework.web.bind.annotation.ModelAttribute;
137
import org.springframework.web.bind.annotation.RequestMapping;
148
import org.springframework.web.bind.annotation.RequestParam;
159
import org.springframework.web.bind.annotation.RestController;
16-
import org.springframework.web.client.RestTemplate;
17-
import org.springframework.web.util.UriComponentsBuilder;
1810

19-
import com.example.log4u.common.oauth2.dto.CustomOAuth2User;
20-
import com.example.log4u.domain.map.dto.MyLocationRequestDto;
21-
import com.example.log4u.domain.map.dto.ReverseGeocodingResponseDto;
2211
import com.example.log4u.domain.map.dto.response.DiaryClusterResponseDto;
2312
import com.example.log4u.domain.map.dto.response.DiaryMarkerResponseDto;
2413
import com.example.log4u.domain.map.service.MapService;
@@ -37,7 +26,7 @@ public class MapController {
3726
private final MapService mapService;
3827

3928
@GetMapping("/diaries/cluster")
40-
public ResponseEntity<List<DiaryClusterResponseDto>> getDiaryClustersByGeohash(
29+
public ResponseEntity<List<DiaryClusterResponseDto>> getDiaryClusters(
4130
@RequestParam String geohash,
4231
@RequestParam int level
4332
) {
@@ -46,8 +35,8 @@ public ResponseEntity<List<DiaryClusterResponseDto>> getDiaryClustersByGeohash(
4635
}
4736

4837
@GetMapping("/diaries/marker")
49-
public ResponseEntity<List<DiaryMarkerResponseDto>> getDiariesByGeohash(@RequestParam String geohash) {
50-
List<DiaryMarkerResponseDto> diaries = mapService.getDiariesByGeohash(geohash);
38+
public ResponseEntity<List<DiaryMarkerResponseDto>> getDiaryMarkers(@RequestParam String geohash) {
39+
List<DiaryMarkerResponseDto> diaries = mapService.getDiaryMarkers(geohash);
5140
return ResponseEntity.ok(diaries);
5241
}
5342
}

0 commit comments

Comments
 (0)