Skip to content

Commit

Permalink
Merge pull request #3 from Oh-Lottery/crawler2
Browse files Browse the repository at this point in the history
Auto Crawler 완성
  • Loading branch information
SalkCoding authored Dec 10, 2024
2 parents 69fe6b4 + 5816cf4 commit a73fa03
Show file tree
Hide file tree
Showing 14 changed files with 375 additions and 35 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// 웹 크롤링을 위해 추가한 라이브러리
implementation 'org.jsoup:jsoup:1.16.1'
implementation 'org.springframework.boot:spring-boot-starter-aop'
}

tasks.named('test') {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/ohlottery/OhLotteryApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
public class OhLotteryApplication {

Expand Down
30 changes: 15 additions & 15 deletions src/main/java/com/ohlottery/controller/Lottery645Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,21 @@ public ResponseEntity<?> getLotteryNumber(
if (roundResult.isEmpty()) return ResponseEntity.notFound().build();

Lottery645Entity resultEntity = roundResult.get();
Lottery645Dto resultDto = Lottery645Dto.builder()
.round(resultEntity.getRound())
.bonusNo(resultEntity.getBonusNo())
.drawDate(resultEntity.getDrawDate())
.drawNo1(resultEntity.getDrawNo1())
.drawNo2(resultEntity.getDrawNo2())
.drawNo3(resultEntity.getDrawNo3())
.drawNo4(resultEntity.getDrawNo4())
.drawNo5(resultEntity.getDrawNo5())
.drawNo6(resultEntity.getDrawNo6())
.firstAccumulateAmount(resultEntity.getFirstAccumulateAmount())
.firstPrizeWinnerCount(resultEntity.getFirstPrizeWinnerCount())
.totalSellAmount(resultEntity.getTotalSellAmount())
.firstWinAmount(resultEntity.getFirstWinAmount())
.build();
Lottery645Dto resultDto = new Lottery645Dto(
resultEntity.getRound(),
resultEntity.getDrawDate(),
resultEntity.getDrawNo1(),
resultEntity.getDrawNo2(),
resultEntity.getDrawNo3(),
resultEntity.getDrawNo4(),
resultEntity.getDrawNo5(),
resultEntity.getDrawNo6(),
resultEntity.getBonusNo(),
resultEntity.getFirstAccumulateAmount(),
resultEntity.getFirstPrizeWinnerCount(),
resultEntity.getFirstWinAmount(),
resultEntity.getTotalSellAmount()
);
return ResponseEntity.ok(resultDto);
}
}
14 changes: 7 additions & 7 deletions src/main/java/com/ohlottery/controller/Lottery720Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ public ResponseEntity<?> getLotteryNumber(
if (roundResult.isEmpty()) return ResponseEntity.notFound().build();

Lottery720Entity resultEntity = roundResult.get();
Lottery720Dto resultDto = Lottery720Dto.builder()
.round(resultEntity.getRound())
.drawDate(resultEntity.getDrawDate())
.rankClass(resultEntity.getRankClass())
.rankNo(resultEntity.getRankNo())
.rankWinNum(resultEntity.getRankWinNum())
.build();
Lottery720Dto resultDto = new Lottery720Dto(
resultEntity.getRound(),
resultEntity.getDrawDate(),
resultEntity.getRankWinNum(),
resultEntity.getRankClass(),
resultEntity.getRankNo()
);
return ResponseEntity.ok(resultDto);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.ohlottery.controller;

import com.ohlottery.service.DHLotteryCrawlerService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//Authentication 과정 필수로 필요

@RestController
@RequestMapping("/crawler")
@RequiredArgsConstructor
public class LotteryCrawlerController {

private final DHLotteryCrawlerService lotteryCrawlerService;

@PatchMapping("/lottery645/{round}")
public ResponseEntity<Void> fetchLottery645(@PathVariable long round) {
lotteryCrawlerService.fetchLottery645Data(round);
return ResponseEntity.ok().build();
}

@PatchMapping("/lottery720/{round}")
public ResponseEntity<Void> fetchLottery720(@PathVariable long round) {
lotteryCrawlerService.fetchLottery720Data(round);
return ResponseEntity.ok().build();
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/ohlottery/dto/Lottery645Dto.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.ohlottery.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.time.LocalDate;

@Data
@Builder
@AllArgsConstructor
@Schema(description = "6/45 로또 정보")
public class Lottery645Dto {

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/ohlottery/dto/Lottery720Dto.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.ohlottery.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.time.LocalDate;

@Data
@Builder
@AllArgsConstructor
@Schema(description = "연금복권 정보")
public class Lottery720Dto {

Expand All @@ -18,7 +18,7 @@ public class Lottery720Dto {
private LocalDate drawDate;

@Schema(description = "등수", example = "1")
private short rankWinNum;
private int rankWinNum;

@Schema(description = "당첨 조 번호", example = "4")
private int rankClass;
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/ohlottery/entity/Lottery645Entity.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.ohlottery.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.*;

import java.time.LocalDate;

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Lottery645Entity {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long round;

private LocalDate drawDate;
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/ohlottery/entity/Lottery720Entity.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.ohlottery.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.*;

import java.time.LocalDate;

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Lottery720Entity {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long round;// 회차

private LocalDate drawDate;// 추첨 날짜

private short rankWinNum;// 등수
private byte rankWinNum;// 등수
private byte rankClass;// 조 번호
private int rankNo;// 당첨 번호
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@

import com.ohlottery.entity.Lottery645Entity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface Lottery645Repository extends JpaRepository<Lottery645Entity, Long> {

boolean existsByRound(long round);

@Query("SELECT COALESCE(MAX(l.round), 0) FROM Lottery645Entity l")
int findMaxRound();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

import com.ohlottery.entity.Lottery720Entity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface Lottery720Repository extends JpaRepository<Lottery720Entity, Long> {
boolean existsByRound(long round);
@Query("SELECT COALESCE(MAX(l.round), 0) FROM Lottery720Entity l")
int findMaxRound();

}
85 changes: 85 additions & 0 deletions src/main/java/com/ohlottery/scheduler/LotteryCrawlerScheduler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.ohlottery.scheduler;

import com.ohlottery.service.DHLotteryCrawlerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@RequiredArgsConstructor
public class LotteryCrawlerScheduler {

private final DHLotteryCrawlerService lotteryCrawlerService;

@Scheduled(cron = "0 35 20 * * 6") // 매주 토요일 20:35
public void scheduleFetchLottery645Data() {
log.info("Scheduled Task: fetchLottery645Data 실행 중");
try {
int latestRound = getLatestLottery645Round();
log.info("가져온 최신 6/45 로또 회차: {}", latestRound);
scheduleRetryFetch(() -> lotteryCrawlerService.fetchLottery645Data(latestRound), "6/45", latestRound);
} catch (Exception e) {
log.error("fetchLottery645Data 실행 중 에러 발생", e);
}
}

@Scheduled(cron = "0 5 19 * * 4") // 매주 목요일 19:05
public void scheduleFetchLottery720Data() {
log.info("Scheduled Task: fetchLottery720Data 실행 중");
try {
int latestRound = getLatestLottery720Round();
log.info("가져온 최신 720 로또 회차: {}", latestRound);
scheduleRetryFetch(() -> lotteryCrawlerService.fetchLottery720Data(latestRound), "720", latestRound);
} catch (Exception e) {
log.error("fetchLottery720Data 실행 중 에러 발생", e);
}
}

private void scheduleRetryFetch(Runnable fetchTask, String lotteryType, int round) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
final int[] retryCount = {0}; // 재시도 횟수
final int maxRetries = 12; // 최대 12번 재시도 (5분 x 12 = 1시간)

executor.scheduleAtFixedRate(() -> {
try {
log.info("재시도 실행 중: {} 로또 회차 {} | 시도 횟수: {}/{}", lotteryType, round, retryCount[0] + 1, maxRetries);
fetchTask.run();
log.info("재시도 성공: {} 로또 회차 {}", lotteryType, round);
executor.shutdown(); // 성공하면 재시도 종료
} catch (Exception e) {
retryCount[0]++;
log.error("재시도 실패: {} 로또 회차 {} | 시도 횟수: {}/{}", lotteryType, round, retryCount[0], maxRetries, e);
if (retryCount[0] >= maxRetries) {
log.error("재시도 횟수 초과로 중단: {} 로또 회차 {}", lotteryType, round);
executor.shutdown(); // 최대 재시도 횟수 초과 시 종료
}
}
}, 0, 5, TimeUnit.MINUTES); // 즉시 실행, 이후 5분 간격
}

private int getLatestLottery645Round() {
try {
int latestRound = lotteryCrawlerService.getLatest645Round();
return latestRound + 1;
} catch (Exception e) {
log.error("6/45 최신 회차를 가져오는 중 에러 발생", e);
return -1;
}
}

private int getLatestLottery720Round() {
try {
int latestRound = lotteryCrawlerService.getLatest720Round();
return latestRound + 1;
} catch (Exception e) {
log.error("720 최신 회차를 가져오는 중 에러 발생", e);
return -1;
}
}
}
Loading

0 comments on commit a73fa03

Please sign in to comment.