본문 바로가기

Playlist/Spring Batch

MovieTasklet

*/domain/content/batch

 

import com.codeit.playlist.domain.content.api.mapper.TmdbMapper;
import com.codeit.playlist.domain.content.api.response.TheMovieResponse;
import com.codeit.playlist.domain.content.api.service.TheMovieApiService;
import com.codeit.playlist.domain.content.entity.Content;
import com.codeit.playlist.domain.content.repository.ContentRepository;
import com.codeit.playlist.domain.content.service.TagService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class MovieTasklet implements Tasklet {
    private final TheMovieApiService theMovieApiService;
    private final TmdbMapper theMovieMapper;
    private final ContentRepository contentRepository;
    private final TagService tagService;

    @Override
    @Transactional
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        log.info("[콘텐츠 데이터 관리] TMDB The Movie API 데이터 배치 수집 시작");

        String query = "language=ko-KR";
        int invalidCount = 0;
        int existCount = 0;
        int languageCount = 0;

        List<TheMovieResponse> movieResponseList = theMovieApiService.getApiMovie(query)
                .doOnError(e -> log.error("[콘텐츠 데이터 관리] The Movie 배치 Tasklet 스트림 에러 발생 : {}", e.getMessage(), e))
                .doOnComplete(() -> log.info("[콘텐츠 데이터 관리] The Movie 배치 Tasklet 스트림 동작 완료, API 데이터 수집"))
                .collectList()
                .block();

        if(movieResponseList == null || movieResponseList.isEmpty()) {
            return RepeatStatus.FINISHED;
        }

        for(int i = 0; i< movieResponseList.size(); i++) {
            TheMovieResponse movieResponse = movieResponseList.get(i);
            Content content = theMovieMapper.toContent(movieResponse, "movie");
            String thumbnailUrl = movieResponse.thumbnailUrl();

            if(movieResponse.apiId() == null) { // tmdb id가 없음
                continue;
            }

            Long tmdbId = movieResponse.apiId();
            if(contentRepository.existsByApiId(tmdbId)) { // tmdbId가 이미 있음
                existCount++;
                continue;
            }

            if(thumbnailUrl != null && !thumbnailUrl.isBlank()) {
                content.setThumbnailUrl("https://image.tmdb.org/t/p/w500" + thumbnailUrl);
            }

            if(movieResponse.description() == null || movieResponse.description().isBlank()) { // 설명이 없음
                invalidCount++;
                continue;
            }

            if(movieResponse.title() == null) { // 타이틀이 없음
                continue;
            }

            Content resultContent = contentRepository.save(content); // 썸네일까지 set된 content

            if(movieResponse.genreIds() != null && !movieResponse.genreIds().isEmpty()) {
                tagService.saveMovieTagToContent(resultContent, movieResponse.genreIds());
            }
        }
        log.debug("[콘텐츠 데이터 관리] TMDB The Movie API에서 한글이 한글자도 없는 콘텐츠 횟수 : {}", languageCount);
        log.debug("[콘텐츠 데이터 관리] TMDB The Movie API가 이만큼 비어있었어요. count : {}", invalidCount);
        log.debug("[콘텐츠 데이터 관리] TMDB The Movie API contents가 이만큼 없어요. count : {}", existCount);
        log.debug("[콘텐츠 데이터 관리] The Movie API 콘텐츠와 태그 수집 완료");
        return RepeatStatus.FINISHED;
    }
}

'Playlist > Spring Batch' 카테고리의 다른 글

BatchConfig  (0) 2025.12.17
SportContentTasklet  (0) 2025.12.17
TvSeriesTasklet  (0) 2025.12.17
ContentScheduler  (0) 2025.12.17
Spring Batch, 배치  (0) 2025.11.14