diff --git a/customer-service/src/main/java/com/example/customerservice/actor/entity/Actor.java b/customer-service/src/main/java/com/example/customerservice/actor/entity/Actor.java new file mode 100644 index 0000000..c41eeb2 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/entity/Actor.java @@ -0,0 +1,40 @@ +package com.example.customerservice.actor.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +import static jakarta.persistence.CascadeType.ALL; + +@Entity +@Table(name = "actor") +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Actor { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "actor_id") + private Long id; + + @Column(name = "actor_name", length = 30, nullable = false) + private String actorName; + + @OneToMany(mappedBy = "actor", cascade = ALL) + private List actorAppearances = new ArrayList<>(); + + @Builder + private Actor(String actorName) { + this.actorName = actorName; + } + + public static Actor of(String actorName) { + return Actor.builder() + .actorName(actorName) + .build(); + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/entity/ActorAppearances.java b/customer-service/src/main/java/com/example/customerservice/actor/entity/ActorAppearances.java new file mode 100644 index 0000000..3bf7df0 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/entity/ActorAppearances.java @@ -0,0 +1,54 @@ +package com.example.customerservice.actor.entity; + +import com.example.customerservice.contents.entity.Contents; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import static jakarta.persistence.FetchType.LAZY; + +@Entity +@Table(name = "actor_appearances") +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ActorAppearances { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "actor_appearances_id") + private Long id; + + @JsonIgnore + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "contents_id") + private Contents contents; + + @JsonIgnore + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "actor_id") + private Actor actor; + + @Builder + private ActorAppearances(Contents contents, Actor actor) { + setContents(contents); + setActor(actor); + } + + public static ActorAppearances of(Contents contents, Actor actor) { + return ActorAppearances.builder() + .contents(contents) + .actor(actor) + .build(); + } + + private void setContents(Contents contents) { + this.contents = contents; + contents.getActorAppearances().add(this); + } + private void setActor(Actor actor) { + this.actor = actor; + actor.getActorAppearances().add(this); + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorAppearancesRepository.java b/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorAppearancesRepository.java new file mode 100644 index 0000000..87730a8 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorAppearancesRepository.java @@ -0,0 +1,7 @@ +package com.example.customerservice.actor.repository; + +import com.example.customerservice.actor.entity.ActorAppearances; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ActorAppearancesRepository extends JpaRepository { +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorRepository.java b/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorRepository.java new file mode 100644 index 0000000..b532bab --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/repository/ActorRepository.java @@ -0,0 +1,11 @@ +package com.example.customerservice.actor.repository; + +import com.example.customerservice.actor.entity.Actor; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface ActorRepository extends JpaRepository { + + Optional findByActorName(String actorName); +} diff --git a/customer-service/src/main/java/com/example/customerservice/config/MovieSchedulerConfig.java b/customer-service/src/main/java/com/example/customerservice/config/MovieSchedulerConfig.java new file mode 100644 index 0000000..9f8d096 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/config/MovieSchedulerConfig.java @@ -0,0 +1,18 @@ +package com.example.customerservice.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +@Configuration +public class MovieSchedulerConfig { + + @Bean(name = "movieTaskScheduler") + public ThreadPoolTaskScheduler movieTaskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(5); + scheduler.setThreadNamePrefix("MovieUpdateScheduler-"); + scheduler.initialize(); + return scheduler; + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/contents/entity/Contents.java b/customer-service/src/main/java/com/example/customerservice/contents/entity/Contents.java index ab82072..46108d7 100644 --- a/customer-service/src/main/java/com/example/customerservice/contents/entity/Contents.java +++ b/customer-service/src/main/java/com/example/customerservice/contents/entity/Contents.java @@ -1,10 +1,16 @@ package com.example.customerservice.contents.entity; +import com.example.customerservice.actor.entity.ActorAppearances; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.ArrayList; +import java.util.List; + +import static jakarta.persistence.CascadeType.ALL; + @Getter @Entity @Table(name="contents") @@ -34,6 +40,9 @@ public class Contents { @Column private Long heartCount; + @OneToMany(mappedBy = "contents", cascade = ALL) + private List actorAppearances = new ArrayList<>(); + @Builder public Contents(String category, String title, String writer, String summary, String image, Long heartCount) { this.category = category; diff --git a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java index 3ba338e..b2b805f 100644 --- a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java +++ b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java @@ -9,4 +9,6 @@ public interface ContentsRepository extends JpaRepository { @Query("SELECT CONCAT(c.title, '|', c.writer) FROM Contents c") List findAllTitlesAndWriters(); + + boolean existsByTitle(String title); } diff --git a/customer-service/src/main/java/com/example/customerservice/movie/client/MovieApiClient.java b/customer-service/src/main/java/com/example/customerservice/movie/client/MovieApiClient.java new file mode 100644 index 0000000..9eb49ba --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/movie/client/MovieApiClient.java @@ -0,0 +1,155 @@ +package com.example.customerservice.movie.client; + +import com.example.customerservice.movie.dto.KoficMovieInfoDto; +import com.example.customerservice.movie.dto.KoficMovieListDto; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@Slf4j +@Component +public class MovieApiClient { + + private final RestTemplate restTemplate; + private final String KOFIC_URL = "https://kobis.or.kr/kobisopenapi/webservice/rest/movie"; + private final String API_KEY; + + public MovieApiClient(@Value("${kofic.key}") String API_KEY) { + this.restTemplate = new RestTemplate(); + this.API_KEY = API_KEY; + } + + /** + * 1 전체 페이지를 조회합니다. + */ + public Integer fetchMoviesTotalsCount() { + LocalDate today = LocalDate.now(); + + String date = today.format(DateTimeFormatter.ofPattern("yyyy")); + + URI uri = UriComponentsBuilder.fromUriString(KOFIC_URL + "/searchMovieList.json") + .queryParam("key", API_KEY) + .queryParam("curPage", "1") + .queryParam("itemPerPage", "100") + .queryParam("openStartDt", date) + .build() + .toUri(); + + try { + String response = restTemplate.getForObject(uri, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + KoficMovieListDto koficMovieListDto = objectMapper.readValue(response, KoficMovieListDto.class); + + return koficMovieListDto.getMovieListResult().getTotalCount(); + } catch (Exception e) { + throw new RuntimeException("Failed", e); + } + } + + /** + * 2 영화를 조회합니다. + */ + public KoficMovieListDto fetchMovie(int page, int maxResults) { + LocalDate today = LocalDate.now(); + String date = today.format(DateTimeFormatter.ofPattern("yyyy")); + + URI uri = UriComponentsBuilder.fromUriString(KOFIC_URL + "/searchMovieList.json") + .queryParam("key", API_KEY) + .queryParam("curPage", page) + .queryParam("itemPerPage", maxResults) + .queryParam("openStartDt", date) + .build() + .toUri(); + + try { + String response = restTemplate.getForObject(uri, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(response, KoficMovieListDto.class); + } catch (Exception e) { + throw new RuntimeException("Failed to fetch movie data", e); + } + } + + /** + * 3 배우를 조회 합니다. + */ + public KoficMovieInfoDto fetchActor(String movieCode) { + + URI uri = UriComponentsBuilder.fromUriString(KOFIC_URL + "/searchMovieInfo.json") + .queryParam("key", API_KEY) + .queryParam("movieCd", movieCode) + .build() + .toUri(); + + try { + String response = restTemplate.getForObject(uri, String.class); + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(response, KoficMovieInfoDto.class); + } catch (Exception e) { + throw new RuntimeException("Failed", e); + } + } + + + /** + * batch 에 사용합니다. + * 요청이 많아지면 API 키 만료 되서 사용 X + */ +// public KoficMovieListDto fetchBathMovie(int page, int maxResults) { +// LocalDate today = LocalDate.now(); +// +// String startDate = today.minusYears(2).format(DateTimeFormatter.ofPattern("yyyy")); +// String endDate = today.format(DateTimeFormatter.ofPattern("yyyy")); +// +// URI uri = UriComponentsBuilder.fromUriString(KOFIC_URL + "/searchMovieList.json") +// .queryParam("key", API_KEY) +// .queryParam("curPage", page) +// .queryParam("itemPerPage", maxResults) +// .queryParam("openStartDt", startDate) +// .queryParam("openEndDt", endDate) +// .build() +// .toUri(); +// +// try { +// String response = restTemplate.getForObject(uri, String.class); +// ObjectMapper objectMapper = new ObjectMapper(); +// return objectMapper.readValue(response, KoficMovieListDto.class); +// } catch (Exception e) { +// throw new RuntimeException("Failed", e); +// } +// } + +// public Integer fetchMoviesTotalsCount() { +// LocalDate today = LocalDate.now(); +// +// String startDate = today.minusYears(2).format(DateTimeFormatter.ofPattern("yyyy")); +// String endDate = today.format(DateTimeFormatter.ofPattern("yyyy")); +// +// URI uri = UriComponentsBuilder.fromUriString(KOFIC_URL + "/searchMovieList.json") +// .queryParam("key", API_KEY) +// .queryParam("curPage", "1") +// .queryParam("itemPerPage", "10") +// .queryParam("openStartDt", startDate) +// .queryParam("openEndDt", endDate) +// .build() +// .toUri(); +// +// try { +// String response = restTemplate.getForObject(uri, String.class); +// ObjectMapper objectMapper = new ObjectMapper(); +// KoficMovieListDto koficMovieListDto = objectMapper.readValue(response, KoficMovieListDto.class); +// +// return koficMovieListDto.getMovieListResult().getTotalCount(); +// } catch (Exception e) { +// throw new RuntimeException("Failed", e); +// } +// } +} \ No newline at end of file diff --git a/customer-service/src/main/java/com/example/customerservice/movie/controller/MovieController.java b/customer-service/src/main/java/com/example/customerservice/movie/controller/MovieController.java new file mode 100644 index 0000000..8bdfa9a --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/movie/controller/MovieController.java @@ -0,0 +1,37 @@ +package com.example.customerservice.movie.controller; + +import com.example.customerservice.contents.entity.SchedulerStatus; +import com.example.customerservice.movie.service.MovieSchedulerService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/movies") +public class MovieController { + + private final MovieSchedulerService movieSchedulerService; + + @PostMapping("/start") + public ResponseEntity startScheduler() { + SchedulerStatus status = movieSchedulerService.startMovieSync(true); + return ResponseEntity.ok(status); + } + + @PostMapping("/stop") + public ResponseEntity stopScheduler() { + SchedulerStatus status = movieSchedulerService.stopMovieSync(); + return ResponseEntity.ok(status); + } + + /** 요청이 많아지면 API 키 만료 되서 사용 X **/ +// @GetMapping("/batch") +// public String startBath() { +// movieSchedulerService.startBathSaveMovie(); +// return "success"; +// } +} diff --git a/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieInfoDto.java b/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieInfoDto.java new file mode 100644 index 0000000..f7a6aef --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieInfoDto.java @@ -0,0 +1,57 @@ +package com.example.customerservice.movie.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class KoficMovieInfoDto { + @JsonProperty("movieInfoResult") + private MovieInfoResult movieInfoResult; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MovieInfoResult { + @JsonProperty("movieInfo") + private MovieInfo movieInfo; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MovieInfo { + @JsonProperty("movieCd") + private String movieCode; + @JsonProperty("movieNm") + private String movieName; + @JsonProperty("genres") + private List genres; + @JsonProperty("directors") + private List directors; + @JsonProperty("actors") + private List actors; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Genres { + @JsonProperty("genreNm") + private String genreName; + } + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Directors { + @JsonProperty("peopleNm") + private String name; + } + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Actors { + @JsonProperty("peopleNm") + private String name; + } + } + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieListDto.java b/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieListDto.java new file mode 100644 index 0000000..d4a2db2 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/movie/dto/KoficMovieListDto.java @@ -0,0 +1,34 @@ +package com.example.customerservice.movie.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class KoficMovieListDto { + @JsonProperty("movieListResult") + private MovieListResult movieListResult; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MovieListResult { + @JsonProperty("totCnt") + private int totalCount; + @JsonProperty("movieList") + private List movieList; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MovieList { + @JsonProperty("movieCd") + private String movieCode; + @JsonProperty("movieNm") + private String movieName; + @JsonProperty("openDt") + private String openDt; + } + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/movie/service/MovieSchedulerService.java b/customer-service/src/main/java/com/example/customerservice/movie/service/MovieSchedulerService.java new file mode 100644 index 0000000..601259d --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/movie/service/MovieSchedulerService.java @@ -0,0 +1,192 @@ +package com.example.customerservice.movie.service; + +import com.example.customerservice.actor.entity.Actor; +import com.example.customerservice.actor.entity.ActorAppearances; +import com.example.customerservice.actor.repository.ActorAppearancesRepository; +import com.example.customerservice.actor.repository.ActorRepository; +import com.example.customerservice.contents.entity.Contents; +import com.example.customerservice.contents.entity.SchedulerStatus; +import com.example.customerservice.contents.repository.ContentsRepository; +import com.example.customerservice.movie.client.MovieApiClient; +import com.example.customerservice.movie.dto.KoficMovieInfoDto; + +import com.example.customerservice.movie.dto.KoficMovieListDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.List; +import java.util.TimeZone; +import java.util.concurrent.ScheduledFuture; + +import static com.example.customerservice.movie.dto.KoficMovieListDto.MovieListResult.*; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MovieSchedulerService { + + private final MovieApiClient movieApiClient; + private final ContentsRepository contentsRepository; + private final ActorRepository actorRepository; + private final ActorAppearancesRepository actorAppearancesRepository; + + @Qualifier("movieTaskScheduler") + private final ThreadPoolTaskScheduler movieTaskScheduler; + + private final Integer maxItemCount = 100; + private ScheduledFuture scheduledTask; + + private static final String TEST_CRON_EXPRESSION = "0/30 * * * * *"; // 테스트용: 15초마다 + private static final String PROD_CRON_EXPRESSION = "0 0 0 ? * WED"; // 배포용: 매주 수요일 자정 + + /** + * 스케줄 + */ + public SchedulerStatus startMovieSync(boolean isTestMode) { //TODO: 테스트 용 불린값을 제외 해야한다. + if (scheduledTask != null && !scheduledTask.isCancelled()) { + log.warn("Movie synchronization scheduler is already running."); + return SchedulerStatus.ALREADY_RUNNING; + } + + String cronExpression = isTestMode ? TEST_CRON_EXPRESSION : PROD_CRON_EXPRESSION; + scheduledTask = movieTaskScheduler.schedule(this::saveMovieAndActor, + new CronTrigger(cronExpression, TimeZone.getTimeZone("Asia/Seoul"))); + + log.info("Movie synchronization scheduler started with cron: {}", cronExpression); + return SchedulerStatus.STARTED; + } + + + public SchedulerStatus stopMovieSync() { + if (scheduledTask != null) { + scheduledTask.cancel(true); + log.info("Movie synchronization scheduler stopped."); + return SchedulerStatus.STOPPED; + } + log.warn("No movie synchronization scheduler task running to stop."); + return SchedulerStatus.NO_TASK_RUNNING; + } + + @Transactional + public void saveMovieAndActor() { + int totalPages = checkTotalPages(); + for (int i = 1; i <= totalPages; i++) { + KoficMovieListDto koficMovieListDto = movieApiClient.fetchMovie(totalPages, maxItemCount); + List movieList = koficMovieListDto.getMovieListResult().getMovieList(); + + movieList.forEach(movieListItem -> { + if (isReleasedWithinAWeek(movieListItem.getOpenDt()) + && !contentsRepository.existsByTitle(movieListItem.getMovieName())) { + processMovieAndActors(movieListItem); + } + }); + } + } + + /** + * 영화와 배우 정보를 처리하는 메서드 + */ + private void processMovieAndActors(MovieList movieListItem) { + KoficMovieInfoDto movieInfoDto = movieApiClient.fetchActor(movieListItem.getMovieCode()); + + String director = extractDirector(movieInfoDto); + String genreName = extractGenre(movieInfoDto); + + Contents savedContent = saveMovieContent(movieListItem, director, genreName); + saveActorsAndMappings(movieInfoDto, savedContent); + } + + /** + * 감독 정보를 추출하는 메서드 + */ + private String extractDirector(KoficMovieInfoDto movieInfoDto) { + return movieInfoDto.getMovieInfoResult().getMovieInfo().getDirectors().isEmpty() + ? "Unknown" + : movieInfoDto.getMovieInfoResult().getMovieInfo().getDirectors().get(0).getName(); + } + + /** + * 장르 정보를 추출하는 메서드 + */ + private String extractGenre(KoficMovieInfoDto movieInfoDto) { + return movieInfoDto.getMovieInfoResult().getMovieInfo().getGenres().isEmpty() + ? "Unknown" + : movieInfoDto.getMovieInfoResult().getMovieInfo().getGenres().get(0).getGenreName(); + } + + /** + * 영화 정보를 저장하는 메서드 + */ + private Contents saveMovieContent(MovieList movieListItem, String director, String genreName) { + Contents content = Contents.of("MOVIE", movieListItem.getMovieName(), director, genreName, ""); + return contentsRepository.save(content); + } + + /** + * 배우 정보를 저장하고 영화와의 매핑을 처리하는 메서드 + */ + private void saveActorsAndMappings(KoficMovieInfoDto movieInfoDto, Contents savedContent) { + List actors = + movieInfoDto.getMovieInfoResult().getMovieInfo().getActors(); + + actors.forEach(actor -> { + Actor savedActor = actorRepository.findByActorName(actor.getName()) + .orElseGet(() -> actorRepository.save(Actor.of(actor.getName()))); + + actorAppearancesRepository.save(ActorAppearances.of(savedContent, savedActor)); + }); + } + + /** + * 개봉일이 일주일 이내인지 확인하는 메서드 + */ + private boolean isReleasedWithinAWeek(String openDt) { + if (openDt == null || openDt.isBlank()) { + return false; + } + + try { + LocalDate releaseDate = LocalDate.parse(openDt, DateTimeFormatter.ofPattern("yyyyMMdd")); + LocalDate today = LocalDate.now(); + LocalDate oneWeekAgo = today.minusDays(7); + + return !releaseDate.isBefore(oneWeekAgo) && !releaseDate.isAfter(today); + } catch (DateTimeParseException e) { + System.err.println("Invalid date format: " + openDt); + return false; + } + } + + private int checkTotalPages() { + Integer totalCount = movieApiClient.fetchMoviesTotalsCount(); + return Math.max((int) Math.ceil((double) totalCount / maxItemCount), 1); + } + + + /** + * 배치 개발 + * 요청이 많아지면 API 키 만료 되서 사용 X + */ +// @Transactional +// public void startBathSaveMovie() { +// Integer totalPages = checkTotalPages(); +// for (int page = 1; page < totalPages; page++) { +// KoficMovieListDto koficMovieListDto = movieApiClient.fetchBathMovie(page, maxItemCount); +// List movieList = koficMovieListDto.getMovieListResult().getMovieList(); +// +// movieList.forEach(movieListItem -> { +// if (!contentsRepository.existsByTitle(movieListItem.getMovieName())) { +// processMovieAndActors(movieListItem); +// } +// }); +// } +// } +}