@@ -53,6 +53,8 @@ public class KopisApiService {
5353
5454 private final ConcertRedisRepository concertRedisRepository ;
5555
56+ private final ConcertService concertService ;
57+
5658 private final ArtistRepository artistRepository ;
5759
5860 private final ConcertArtistRepository concertArtistRepository ;
@@ -73,7 +75,8 @@ public KopisApiService(
7375 ConcertRedisRepository concertRedisRepository ,
7476 ConcertKopisApiLogService kopisApiLogService ,
7577 ArtistRepository artistRepository ,
76- ConcertArtistRepository concertArtistRepository
78+ ConcertArtistRepository concertArtistRepository ,
79+ ConcertService concertService
7780 ) {
7881 this .concertRepository = concertRepository ;
7982 this .placeRepository = placeRepository ;
@@ -83,6 +86,7 @@ public KopisApiService(
8386 this .concertKopisApiLogService = kopisApiLogService ;
8487 this .artistRepository = artistRepository ;
8588 this .concertArtistRepository = concertArtistRepository ;
89+ this .concertService = concertService ;
8690 this .restClient = RestClient .builder ()
8791 .baseUrl ("https://kopis.or.kr/openApi/restful" )
8892 .defaultHeader (HttpHeaders .CONTENT_TYPE , MediaType .APPLICATION_XML_VALUE )
@@ -136,6 +140,7 @@ public void setConcertsList() throws InterruptedException {
136140 // 한국어 실명 기만 artistMap 가져오기
137141 Map <String , Artist > artistMap = getKoNameArtistMap ();
138142
143+ // 개별 공연 항목에 대한 상세 데이터 저장
139144 for (int i = index .intValue (); i < totalConcertsList .size (); i ++) {
140145 ConcertListElement concertListElement = totalConcertsList .get (i );
141146 // API에서 공연 상세 가져오기
@@ -167,7 +172,10 @@ public void setConcertsList() throws InterruptedException {
167172 long endNs = System .currentTimeMillis ();
168173 long durationSec = ((endNs - startNs ) / 1000 );
169174 log .info (durationSec /60 + "분, " + durationSec % 60 + "초 소요되었습니다." );
175+ // 캐시 초기화
170176 cacheClear ();
177+ // 자동 완성 검색어 재설정
178+ resetSearchKeyword ();
171179 } catch (Exception e ) {
172180 log .error ("개별 공연 세부 내용 저장 도중 오류 발생" );
173181 log .error ("오류 내용 : " + e .getMessage ());
@@ -195,73 +203,74 @@ public SetResultResponse updateConcertData() throws InterruptedException {
195203 LocalDate edate = LocalDate .now ().plusYears (1 );
196204
197205 SetResultResponse setResultResponse = new SetResultResponse ();
198-
199- ConcertListResponse plr ;
200- List <ConcertListElement > totalConcertsList = new ArrayList <>();
201206 Map <String , ConcertPlace > concertPlaceMap = new HashMap <>();
202207
203- int page = 1 ;
204- while (true ) {
205- plr = getConcertListResponse (serviceKey , sdate , edate , page , lastUpdatedDate );
206- page ++;
207- if (plr .getConcertList () == null ) break ;
208- for (ConcertListElement p : plr .getConcertList ()) {
209- totalConcertsList .add (p );
210- }
211- Thread .sleep (200 );
212- }
213- log .info ("공연 목록 로드 완료, 공연 세부 내용 로드 및 저장" );
208+ try {
209+ // API에서 공연 목록 가져오기
210+ List <ConcertListElement > totalConcertsList = getConcertListElements (sdate , edate , lastUpdatedDate );
211+ log .info ("공연 목록 로드 완료, 공연 세부 내용 로드 및 저장" );
214212
215- // artist map 가져오기
216- Map <String ,Artist > artistMap = getKoNameArtistMap ();
217- for (ConcertListElement performanceListElement : totalConcertsList ) {
218- ConcertDetailResponse concertDetailResponse = getConcertDetailResponse (serviceKey , performanceListElement .getApiConcertId ());
219- ConcertDetailElement concertDetail = concertDetailResponse .getConcertDetail ();
220- log .info ("concert detail: " + concertDetailResponse .getConcertDetail ());
213+ // artist map 가져오기
214+ Map <String ,Artist > artistMap = getKoNameArtistMap ();
221215
222- // 콘서트 위치 탐색 또는 추가
223- String concertPlaceAPiKey = concertDetailResponse .getConcertDetail ().getMt10id ();
224- ConcertPlace concertPlace = getConcertPlaceOrSaveNewConcertPlace (concertPlaceMap , concertPlaceAPiKey );
216+ // 개별 공연 항목에 대한 상세 데이터 저장
217+ for (ConcertListElement performanceListElement : totalConcertsList ) {
218+ ConcertDetailResponse concertDetailResponse = getConcertDetailResponse (serviceKey , performanceListElement .getApiConcertId ());
219+ ConcertDetailElement concertDetail = concertDetailResponse .getConcertDetail ();
220+ log .info ("concert detail: " + concertDetailResponse .getConcertDetail ());
225221
226- // 콘서트 저장
227- Concert concert = concertRepository .getConcertByApiConcertId (concertDetail .getApiConcertId ());
222+ // 콘서트 위치 탐색 또는 추가
223+ String concertPlaceAPiKey = concertDetailResponse .getConcertDetail ().getMt10id ();
224+ ConcertPlace concertPlace = getConcertPlaceOrSaveNewConcertPlace (concertPlaceMap , concertPlaceAPiKey );
228225
229- if (concert == null ) {
230- // 새 공연 저장
231- Concert savedConcert = saveConcert (concertPlace ,concertDetail );
232- // 공연 예매처 저장
233- setResultResponse .addedTicketOfficeAccumulator (saveConcertTicketOffice (concertDetail , savedConcert ));
234- // 공연 이미지 저장
235- setResultResponse .addedConcertImagesAccumulator (saveConcertImages (concertDetail , savedConcert ));
236- // 공연 아티스트 저장
237- setConcertArtist (artistMap ,concertDetail ,savedConcert );
238- setResultResponse .addConcerts ();
239- } else {
240- // 공연 데이터 갱신 후 저장
241- Concert savedConcert = updateConcert (concert , concertPlace , concertDetail );
242- // 기존에 저장되어 있던 연관 테이블 데이터 삭제
243- ticketOfficeRepository .deleteByConcertId (savedConcert .getConcertId ());
244- imageRepository .deleteByConcertId (savedConcert .getConcertId ());
245- // 갱신된 데이터로 연관 테이블 저장
246- setResultResponse .updatedTicketOfficesAccumulator (saveConcertTicketOffice (concertDetail , savedConcert ));
247- setResultResponse .updatedConcertImagesAccumulator (saveConcertImages (concertDetail , savedConcert ));
248- setResultResponse .addUpdatedConcerts ();
226+ // 콘서트 저장
227+ Concert concert = concertRepository .getConcertByApiConcertId (concertDetail .getApiConcertId ());
228+
229+ if (concert == null ) {
230+ // 새 공연 저장
231+ Concert savedConcert = saveConcert (concertPlace ,concertDetail );
232+ // 공연 예매처 저장
233+ setResultResponse .addedTicketOfficeAccumulator (saveConcertTicketOffice (concertDetail , savedConcert ));
234+ // 공연 이미지 저장
235+ setResultResponse .addedConcertImagesAccumulator (saveConcertImages (concertDetail , savedConcert ));
236+ // 공연 아티스트 저장
237+ setConcertArtist (artistMap ,concertDetail ,savedConcert );
238+ setResultResponse .addConcerts ();
239+ } else {
240+ // 공연 데이터 갱신 후 저장
241+ Concert savedConcert = updateConcert (concert , concertPlace , concertDetail );
242+ // 기존에 저장되어 있던 연관 테이블 데이터 삭제
243+ ticketOfficeRepository .deleteByConcertId (savedConcert .getConcertId ());
244+ imageRepository .deleteByConcertId (savedConcert .getConcertId ());
245+ // 갱신된 데이터로 연관 테이블 저장
246+ setResultResponse .updatedTicketOfficesAccumulator (saveConcertTicketOffice (concertDetail , savedConcert ));
247+ setResultResponse .updatedConcertImagesAccumulator (saveConcertImages (concertDetail , savedConcert ));
248+ setResultResponse .addUpdatedConcerts ();
249+ }
250+
251+ Thread .sleep (300 );
249252 }
250253
251- Thread .sleep (300 );
254+ // 갱신 후 업데이트 시간 저장
255+ concertKopisApiLogService .saveSuccessLog ("save" ,"공연 데이터 업데이트 완료" ,0L );
256+ // 락 해제
257+ concertRedisRepository .unlockSave (key );
258+ // 이전 캐시 데이터 삭제
259+ cacheClear ();
260+ // 자동 완성 검색어 재설정
261+ resetSearchKeyword ();
262+ return setResultResponse ;
263+ } catch (Exception e ) {
264+ log .error ("공연 정보 갱신 도중 오류 발생 : " +e .getMessage ());
265+ concertKopisApiLogService .saveErrorLog ("save" ,e ,0L );
266+ } finally {
267+ // 락 해제
268+ concertRedisRepository .unlockSave (key );
252269 }
253-
254- // 갱신 후 업데이트 시간 저장
255- concertKopisApiLogService .saveSuccessLog ("save" ,"공연 데이터 업데이트 완료" ,0L );
256- // 락 해제
257- concertRedisRepository .unlockSave (key );
258- // 이전 캐시 데이터 삭제
259- cacheClear ();
260270 return setResultResponse ;
261271 }
262272
263-
264-
273+ // concertId의 공연만 API에서 갱신
265274 @ Transactional
266275 public void concertUpdateByKopisApi (Long concertId ){
267276 // 해당 콘서트 ID로 콘서트 객체 찾기
@@ -290,11 +299,10 @@ public void concertUpdateByKopisApi(Long concertId){
290299 // 새로 받아온 예매처, 이미지 데이터 저장
291300 saveConcertTicketOffice (concertDetail , savedConcert );
292301 saveConcertImages (concertDetail , savedConcert );
293-
294-
295302 }
296303
297304
305+ // API에서 모든 공연 목록 가져오기
298306 private List <ConcertListElement > getAllConcertsListFromKopisAPI (int page ) throws InterruptedException {
299307 List <ConcertListElement > totalConcertsList = new ArrayList <>();
300308 while (true ) {
@@ -311,6 +319,23 @@ private List<ConcertListElement> getAllConcertsListFromKopisAPI(int page) throws
311319 return totalConcertsList ;
312320 }
313321
322+ // API에서 이전 업데이트 날짜 이후로 변경된 공연 목록 가져오기
323+ private List <ConcertListElement > getConcertListElements (LocalDate sdate , LocalDate edate , LocalDate lastUpdatedDate ) throws InterruptedException {
324+ List <ConcertListElement > totalConcertsList = new ArrayList <>();
325+ int page = 1 ;
326+ while (true ) {
327+ ConcertListResponse plr = getConcertListResponse (serviceKey , sdate , edate , page , lastUpdatedDate );
328+ page ++;
329+ if (plr .getConcertList () == null ) break ;
330+ for (ConcertListElement p : plr .getConcertList ()) {
331+ totalConcertsList .add (p );
332+ }
333+ Thread .sleep (120 );
334+ }
335+ return totalConcertsList ;
336+ }
337+
338+
314339 // 공연 데이터 저장
315340 private Concert saveConcert (ConcertPlace concertPlace , ConcertDetailElement concertDetail ) {
316341 TicketPrice ticketPrice = new TicketPrice (concertDetail .getConcertPrice ());
@@ -427,6 +452,12 @@ private void cacheClear() {
427452 concertRedisRepository .deleteTotalConcertsCount (ListSort .VIEW );
428453 }
429454
455+ // 캐시에 저장된 자동완성 단어들을 삭제하고 다시 설정합니다.
456+ private void resetSearchKeyword () {
457+ concertService .resetAutoComplete ();
458+ concertService .setAutoComplete ();
459+ }
460+
430461 public ConcertListResponse getConcertsList () {
431462 return getConcertListResponse (serviceKey , sdate , edate , 1 );
432463 }
0 commit comments