scheduler 로 자동 갱신 (@Scheduled)

박영준·2023년 7월 26일
0

Spring

목록 보기
49/58

뉴닉 클론 코딩 중 크롤링으로 한겨레에 있는 기사들을 가져왔다.

기사 전체를 조회할 때 DB 에 저장되도록 구성했는데, (직접 저장)
scheduler 를 이용한다면 매번 직접 조회를 하면서 DB 에 저장할 필요 없이 자동적으로 데이터가 갱신된다 (한 번 직접 저장 후에는 계속 자동 갱신)

1. 세팅하기

@EnableScheduling
@SpringBootApplication
public class SixneekApplication {

    public static void main(String[] args) {
        SpringApplication.run(SixneekApplication.class, args);
    }
}

application 에서 @EnableScheduling 를 설정해줘야 한다.

2. CrawlingArticle

예시 1

스케줄링은 간단하다.
크롤링해오는 로직에 @Scheduled(cron = "0 0 /2 * *") 어노테이션만 추가되었을 뿐이다.

단, 기본적으로 void 반환 타입을 사용하며, 매개변수가 없는 메서드이어야 한다.

@Service
@Slf4j(topic = "Scheduler")
@RequiredArgsConstructor
public class CrawlingArticle {
    private final ArticleRepository articleRepository;

    // 크롤링: 전체 기사 조회
    @Scheduled(cron = "0 0 */2 * * *")      // 2시간 마다 기사 업데이트
    public List<ArticleListResponseDto> saveArticleList() throws IOException {
        articleRepository.deleteAll();
        List<ArticleListResponseDto> articleResponseDtoList = new ArrayList<>();
        long currentId = 1;
        for (int i = 1; i <= 10; i++) {
            String Article_URL = "https://www.hani.co.kr/arti/list" + i + ".html";
            articleResponseDtoList.addAll(processUrl(Article_URL, currentId));
            currentId += 15;
        }

        log.info("뉴스 기사 크롤링 완료");

        return articleResponseDtoList;
    }

    // Url 처리하기
    private List<ArticleListResponseDto> processUrl(String url, long currentId) throws IOException {
        Document document = Jsoup.connect(url).get();
        Elements contentList = document.select("div div.section-list-area div.list");

        List<ArticleListResponseDto> articleResponseDtoList = new ArrayList<>();

        for (Element contents : contentList) {
            String image = contents.select("a img").attr("abs:src");        // 이미지
            String title = contents.select("h4 a").text();      // 제목
            String date = contents.select("p span").text().substring(0, 10).replaceAll("-", "/");       // 날짜
            String tag = contents.select("strong a").text();        // 섹션(태그)
            
            String articleLink = contents.select("h4 a").attr("abs:href");      // 내용
            Document articleDocument = Jsoup.connect(articleLink).get();
            String content = articleDocument.select("div div.text").text();

            Article article = Article.builder()
                    .id(currentId++)
                    .image(image)
                    .title(title)
                    .tag(tag)
                    .date(date)
                    .content(content)
                    .build();

            articleRepository.save(article);
            articleResponseDtoList.add(new ArticleListResponseDto(article));
        }

        return articleResponseDtoList;
    }
    
    ...
    
}    

@Slf4j

  • @Slf4j 를 사용한다면, log 인스턴스 를 사용할 수 있게 된다.

    • log 를 통해 scheduler 가 정상적으로 작동했는지 인텔리제이 콘솔창에서 확인할 수 있다
  • topic 은 로그 분류를 위해 사용된다.

@Scheduled(cron = "0 0 */2 * * *")

  • 초, 분, 시, 일, 월, 주 순서

    • 설정해둔 시간이 되면, 인텔리제이 콘솔창에 자동적으로 기록이 찍힌다.
  • @Scheduled 공식문서 에서 업데이트 할 시간을 참고해서 설정할 수 있다.

예시 2

@Slf4j(topic = "Scheduler")
@Service
@RequiredArgsConstructor
public class NotificationScheduler {
    private final NotificationRepository notificationRepository;

    // 6시간 마다 생성일 기준 2일 지난 알림 삭제
    @Scheduled(cron = "0 0 */6 * * *")
    public void deleteNotification() {
        LocalDate twoDaysAgo = LocalDate.now().minusDays(2);
        List<Notification> notificationsToDelete = notificationRepository.findByCreatedAtBefore(twoDaysAgo);

        notificationRepository.deleteAll(notificationsToDelete);

        log.info(notificationsToDelete.size() + "개 알림 삭제 완료");
    }
}
  • 해당 scheduler 메서드를 6시간 마다 실행하게 된다.
    • 이때, JPA 쿼리 메서드를 이용해서, 생성시간으로부터 2일이 지난 데이터만 선택적으로 삭제할 수 있다.

참고: 8. 로그 파일 만들기, 인터셉터 구현하기

profile
개발자로 거듭나기!

0개의 댓글