55import org .springframework .beans .factory .annotation .Value ;
66import org .springframework .data .domain .PageRequest ;
77import org .springframework .stereotype .Service ;
8- import org .springframework .transaction .annotation .Propagation ;
98import org .springframework .transaction .annotation .Transactional ;
109import org .umc .travlocksserver .domain .template .dto .response .VlockSuggestionsResponseDTO ;
1110import org .umc .travlocksserver .domain .template .entity .Template ;
1211import org .umc .travlocksserver .domain .template .entity .TemplateDay ;
1312import org .umc .travlocksserver .domain .template .enums .TransportType ;
1413import org .umc .travlocksserver .domain .template .exception .TemplateDayException ;
1514import org .umc .travlocksserver .domain .template .code .TemplateDayErrorCode ;
16- import org .umc .travlocksserver .domain .template .projection .CityProjectionDTO ;
1715import org .umc .travlocksserver .domain .template .repository .TemplateDayRepository ;
1816import org .umc .travlocksserver .domain .template .service .query .TemplateCityQueryService ;
1917import org .umc .travlocksserver .domain .template .service .query .TemplateQueryService ;
2018import org .umc .travlocksserver .domain .template .service .query .TemplateVlockQueryService ;
2119import org .umc .travlocksserver .domain .vlock .entity .Vlock ;
22- import org .umc .travlocksserver .domain .vlock .service .command .VlockCommandService ;
20+ import org .umc .travlocksserver .domain .vlock .service .command .VlockExternalCommandService ;
2321import org .umc .travlocksserver .domain .vlock .service .query .VlockQueryService ;
2422import org .umc .travlocksserver .global .geo .BoundingBox ;
2523import org .umc .travlocksserver .global .geo .GeoUtil ;
2624import org .umc .travlocksserver .global .geo .LatLng ;
2725import org .umc .travlocksserver .infra .ai .client .AiSuggestionClient ;
2826import org .umc .travlocksserver .infra .ai .dto .ScoredCandidate ;
29- import org .umc .travlocksserver .infra .kakao .KakaoPlaceClient ;
30- import org .umc .travlocksserver .infra .kakao .KakaoPlace ;
3127import org .umc .travlocksserver .infra .redis .vlock .CachedVlockSuggestions ;
3228import org .umc .travlocksserver .infra .redis .vlock .VlockSuggestionCache ;
3329
@@ -55,14 +51,13 @@ public class TemplateDayCommandService {
5551 private final VlockRepository vlockRepository ;
5652
5753 private final TemplateCityQueryService templateCityQueryService ;
58- private final VlockCommandService vlockCommandService ;
54+ private final VlockExternalCommandService vlockExternalCommandService ;
5955 private final TemplateVlockQueryService templateVlockQueryService ;
6056 private final VlockQueryService vlockQueryService ;
6157 private final TemplateQueryService templateQueryService ;
6258
6359 private final VlockSuggestionCache vlockSuggestionCache ;
6460
65- private final KakaoPlaceClient kakaoPlaceClient ;
6661 private final AiSuggestionClient aiClient ;
6762
6863 @ Value ("${suggestion.vlock.popular-pool}" )
@@ -80,9 +75,6 @@ public class TemplateDayCommandService {
8075 @ Value ("${suggestion.vlock.pool-size}" )
8176 private int poolSize ;
8277
83- @ Value ("${kakao.keyword-search.size}" )
84- private int kakaoKeywordSearchSize ;
85-
8678 @ Value ("${suggestion.vlock.size}" )
8779 private int vlockSuggestionSize ;
8880
@@ -301,7 +293,7 @@ private CachedVlockSuggestions buildSuggestion(Template template) {
301293
302294 // 블록 추천 후보 수가 minPool 이하면 외부 API(카카오맵)에서 가져와서 저장
303295 if (candidates .size () < minPool ) {
304- fetchFromExternal (templateId , null , null );
296+ vlockExternalCommandService . fetchFromExternal (templateId , null , null );
305297 candidates = vlockQueryService .getPopularByCityIds (cityIdsOfTemplate , PageRequest .of (0 , popularPool ));
306298 }
307299
@@ -563,51 +555,6 @@ private List<Vlock> findNearVlocksByCenter(
563555 .toList ();
564556 }
565557
566- /**
567- * 카카오맵 API로부터 Vlock들을 추가하는 메서드
568- */
569- @ Transactional (propagation = Propagation .NOT_SUPPORTED )
570- protected void fetchFromExternal (Long templateId , LatLng center , Integer radiusKm ) {
571- List <CityProjectionDTO > cities = templateCityQueryService .getCitiesByTemplateId (templateId );
572- if (cities .isEmpty ())
573- return ;
574-
575- Double x = (center == null ) ? null : center .lng ();
576- Double y = (center == null ) ? null : center .lat ();
577- Integer radiusM = (center == null ) ? null : radiusKm * 1000 ;
578-
579- for (CityProjectionDTO city : cities ) {
580- List <KakaoPlace > results = new ArrayList <>();
581- results .addAll (fetchKakaoPlaces (city .cityName () + " 관광지" , x , y , radiusM ));
582- results .addAll (fetchKakaoPlaces (city .cityName () + " 맛집" , x , y , radiusM ));
583- results .addAll (fetchKakaoPlaces (city .cityName () + " 카페" , x , y , radiusM ));
584-
585- List <KakaoPlace > deduplicated = deduplicateByPlaceId (results );
586-
587- vlockCommandService .upsertVlocksFromExternal (city .cityId (), deduplicated );
588- }
589- }
590-
591- /**
592- * KakaoPlaceId 기준으로 중복되는 결과를 삭제하는 메서드
593- */
594- private List <KakaoPlace > deduplicateByPlaceId (List <KakaoPlace > places ) {
595- Map <String , KakaoPlace > result = new LinkedHashMap <>();
596- for (KakaoPlace place : places ) {
597- if (place .placeId () == null )
598- continue ;
599- result .put (place .placeId (), place );
600- }
601- return new ArrayList <>(result .values ());
602- }
603-
604- /**
605- * 외부(카카오맵) API를 통해 키워드 검색 후 내부 KakaoPlaceDTO로 변환하는 메서드
606- */
607- private List <KakaoPlace > fetchKakaoPlaces (String query , Double lng , Double lat , Integer radiusM ) {
608- return kakaoPlaceClient .searchPlaces (query , lng , lat , radiusM , kakaoKeywordSearchSize );
609- }
610-
611558 /**
612559 * 추천 후보들을 뽑는 메서드
613560 * - 해당 template에 블록이 없는 경우 Vlock 사용수로, 있는 경우 거리 및 Vlock 사용수로 선별
0 commit comments