From d8b8d267bc3fd6c137fdaab6230a3a93b0adc5ea Mon Sep 17 00:00:00 2001 From: SalkCoding Date: Tue, 17 Dec 2024 17:20:38 +0900 Subject: [PATCH 1/2] Add controllers for AI service --- .../controller/Lottery645Controller.java | 4 +- .../controller/Lottery720Controller.java | 4 +- .../controller/LotteryAIController.java | 78 +++++++++++++++++++ .../com/ohlottery/service/LotteryService.java | 5 ++ 4 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/ohlottery/controller/LotteryAIController.java diff --git a/src/main/java/com/ohlottery/controller/Lottery645Controller.java b/src/main/java/com/ohlottery/controller/Lottery645Controller.java index 78203d5..eb24af2 100644 --- a/src/main/java/com/ohlottery/controller/Lottery645Controller.java +++ b/src/main/java/com/ohlottery/controller/Lottery645Controller.java @@ -20,7 +20,7 @@ import java.util.Optional; @RestController -@RequestMapping("lottery645/round") +@RequestMapping("lottery645") @RequiredArgsConstructor @Tag(name = "Lottery 6/45 Controller", description = "6/45 당첨 정보 API") @@ -28,7 +28,7 @@ public class Lottery645Controller { private final LotteryService lotteryService; - @GetMapping("/{round}") + @GetMapping("/round/{round}") @Operation(summary = "6/45로또 데이터 조회", description = "해당 회차 6/45 당첨 정보를 데이터베이스에서 조회") @ApiResponses(value ={ diff --git a/src/main/java/com/ohlottery/controller/Lottery720Controller.java b/src/main/java/com/ohlottery/controller/Lottery720Controller.java index 1339c4b..7197b8e 100644 --- a/src/main/java/com/ohlottery/controller/Lottery720Controller.java +++ b/src/main/java/com/ohlottery/controller/Lottery720Controller.java @@ -20,7 +20,7 @@ import java.util.Optional; @RestController -@RequestMapping("lottery720/round") +@RequestMapping("lottery720") @RequiredArgsConstructor @Tag(name = "Lottery 720 Controller", description = "연금복권 당첨 정보 API") @@ -35,7 +35,7 @@ public class Lottery720Controller { @ApiResponse(responseCode = "400", description = "잘못된 인자 값", content = @Content()), @ApiResponse(responseCode = "404", description = "해당 회차 당첨 정보가 없음", content = @Content()) }) - @GetMapping("/{round}") + @GetMapping("/round/{round}") public ResponseEntity getLotteryNumber( @Parameter(description = "회차", example = "1") @PathVariable("round") Long requestRound diff --git a/src/main/java/com/ohlottery/controller/LotteryAIController.java b/src/main/java/com/ohlottery/controller/LotteryAIController.java new file mode 100644 index 0000000..6fecdbe --- /dev/null +++ b/src/main/java/com/ohlottery/controller/LotteryAIController.java @@ -0,0 +1,78 @@ +package com.ohlottery.controller; + +import com.ohlottery.dto.Lottery645Dto; +import com.ohlottery.dto.Lottery720Dto; +import com.ohlottery.service.LotteryService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/lottery/ai") +public class LotteryAIController { + + private final LotteryService lotteryService; + + @GetMapping("/predict/645/{round}") + public ResponseEntity get645Predict( + @PathVariable long round + ) { + return ResponseEntity.ok( + new Lottery645Dto( + 0, + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ) + ); + } + + @GetMapping("/statistic/645") + public ResponseEntity get645Statistic() { + return ResponseEntity.ok(null); + } + + @GetMapping("/trend/645") + public ResponseEntity get645Trend() { + return ResponseEntity.ok(null); + } + + @GetMapping("/predict/720/{round}") + public ResponseEntity get720Predict( + @PathVariable long round + ) { + return ResponseEntity.ok( + new Lottery720Dto( + 0, + null, + 0, + 0, + 0 + ) + ); + } + + @GetMapping("/statistic/720") + public ResponseEntity get720Statistic() { + return ResponseEntity.ok(null); + } + + @GetMapping("/trend/720") + public ResponseEntity get720Trend() { + return ResponseEntity.ok(null); + } + +} diff --git a/src/main/java/com/ohlottery/service/LotteryService.java b/src/main/java/com/ohlottery/service/LotteryService.java index 5c962ed..ef064ac 100644 --- a/src/main/java/com/ohlottery/service/LotteryService.java +++ b/src/main/java/com/ohlottery/service/LotteryService.java @@ -1,5 +1,6 @@ package com.ohlottery.service; +import com.ohlottery.dto.Lottery645Dto; import com.ohlottery.entity.Lottery645Entity; import com.ohlottery.entity.Lottery720Entity; import com.ohlottery.repository.Lottery645Repository; @@ -24,4 +25,8 @@ public Optional getLottery720Result(long round){ return lottery720Repository.findById(round); } + public Lottery645Dto getPredict645(long rank){ + + } + } From 7e3e742cd6cb87561fc0a83ab3e97445a2538340 Mon Sep 17 00:00:00 2001 From: SalkCoding Date: Tue, 17 Dec 2024 22:35:16 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=EB=AA=85=EB=8B=B9=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=ED=8C=90=EB=A7=A4=EC=B2=98=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/Lottery645Controller.java | 51 +++++- .../controller/Lottery720Controller.java | 58 ++++++- .../controller/LotteryAIController.java | 32 +--- .../com/ohlottery/dto/LotteryStoreDto.java | 21 +++ .../ohlottery/entity/Lottery645Entity.java | 6 + .../entity/Lottery645WinningEntity.java | 18 +++ .../ohlottery/entity/Lottery720Entity.java | 6 + .../ohlottery/entity/LotteryStoreEntity.java | 38 +++++ .../entity/LotteryWinningEntity.java | 23 +++ .../com/ohlottery/entity/WinningType.java | 13 ++ .../entity/middle/Lottery645EntityStore.java | 27 ++++ .../entity/middle/Lottery720EntityStore.java | 27 ++++ .../repository/Lottery720Repository.java | 2 + .../repository/LotteryStoreRepository.java | 12 ++ .../scheduler/LotteryCrawlerScheduler.java | 6 +- .../service/DHLotteryCrawlerService.java | 148 +++++++++++++++++- ...teryService.java => LotteryAIService.java} | 19 ++- 17 files changed, 461 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/ohlottery/dto/LotteryStoreDto.java create mode 100644 src/main/java/com/ohlottery/entity/Lottery645WinningEntity.java create mode 100644 src/main/java/com/ohlottery/entity/LotteryStoreEntity.java create mode 100644 src/main/java/com/ohlottery/entity/LotteryWinningEntity.java create mode 100644 src/main/java/com/ohlottery/entity/WinningType.java create mode 100644 src/main/java/com/ohlottery/entity/middle/Lottery645EntityStore.java create mode 100644 src/main/java/com/ohlottery/entity/middle/Lottery720EntityStore.java create mode 100644 src/main/java/com/ohlottery/repository/LotteryStoreRepository.java rename src/main/java/com/ohlottery/service/{LotteryService.java => LotteryAIService.java} (69%) diff --git a/src/main/java/com/ohlottery/controller/Lottery645Controller.java b/src/main/java/com/ohlottery/controller/Lottery645Controller.java index eb24af2..e335448 100644 --- a/src/main/java/com/ohlottery/controller/Lottery645Controller.java +++ b/src/main/java/com/ohlottery/controller/Lottery645Controller.java @@ -1,8 +1,10 @@ package com.ohlottery.controller; import com.ohlottery.dto.Lottery645Dto; +import com.ohlottery.dto.LotteryStoreDto; import com.ohlottery.entity.Lottery645Entity; -import com.ohlottery.service.LotteryService; +import com.ohlottery.entity.LotteryStoreEntity; +import com.ohlottery.service.LotteryAIService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -17,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; @RestController @@ -26,12 +30,12 @@ @Tag(name = "Lottery 6/45 Controller", description = "6/45 당첨 정보 API") public class Lottery645Controller { - private final LotteryService lotteryService; + private final LotteryAIService lotteryAIService; @GetMapping("/round/{round}") @Operation(summary = "6/45로또 데이터 조회", description = "해당 회차 6/45 당첨 정보를 데이터베이스에서 조회") - @ApiResponses(value ={ + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "데이터 조회 성공", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Lottery645Dto.class))), @ApiResponse(responseCode = "400", description = "잘못된 인자 값", content = @Content()), @@ -49,7 +53,7 @@ public ResponseEntity getLotteryNumber( } Optional roundResult - = lotteryService.getLottery645Result(requestRound); + = lotteryAIService.getLottery645Result(requestRound); if (roundResult.isEmpty()) return ResponseEntity.notFound().build(); @@ -71,4 +75,43 @@ public ResponseEntity getLotteryNumber( ); return ResponseEntity.ok(resultDto); } + + @GetMapping("/round/{round}/store") + + @Operation(summary = "6/45로또 1등 판매처 데이터 조회", description = "해당 회차 6/45 1등 판매처 정보를 데이터베이스에서 조회") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "데이터 조회 성공", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = LotteryStoreDto.class))), + @ApiResponse(responseCode = "400", description = "잘못된 인자 값", content = @Content()), + @ApiResponse(responseCode = "404", description = "해당 회차 당첨 정보가 없음", content = @Content()) + }) + public ResponseEntity getRoundStoreList( + @Parameter(description = "회차", example = "1") + @PathVariable("round") String round + ) { + long requestRound; + try { + requestRound = Long.parseLong(round); + } catch (NumberFormatException e) { + return ResponseEntity.badRequest().build(); + } + + Optional roundResult + = lotteryAIService.getLottery645Result(requestRound); + + if (roundResult.isEmpty()) return ResponseEntity.notFound().build(); + Lottery645Entity entity = roundResult.get(); + + List storeList = new ArrayList<>(); + entity.getStoreList().forEach(entityStore -> { + LotteryStoreEntity storeEntity = entityStore.getStoreEntity(); + storeList.add(new LotteryStoreDto( + storeEntity.getId(), + storeEntity.getStoreName(), + storeEntity.getStoreAddress() + )); + } + ); + return ResponseEntity.ok(storeList); + } } \ No newline at end of file diff --git a/src/main/java/com/ohlottery/controller/Lottery720Controller.java b/src/main/java/com/ohlottery/controller/Lottery720Controller.java index 7197b8e..ee7946f 100644 --- a/src/main/java/com/ohlottery/controller/Lottery720Controller.java +++ b/src/main/java/com/ohlottery/controller/Lottery720Controller.java @@ -1,8 +1,10 @@ package com.ohlottery.controller; import com.ohlottery.dto.Lottery720Dto; +import com.ohlottery.dto.LotteryStoreDto; import com.ohlottery.entity.Lottery720Entity; -import com.ohlottery.service.LotteryService; +import com.ohlottery.entity.LotteryStoreEntity; +import com.ohlottery.service.LotteryAIService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -17,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; @RestController @@ -26,7 +30,7 @@ @Tag(name = "Lottery 720 Controller", description = "연금복권 당첨 정보 API") public class Lottery720Controller { - private final LotteryService lotteryService; + private final LotteryAIService lotteryAIService; @Operation(summary = "연금복권 데이터 조회", description = "해당 회차 연금복권 당첨 정보를 데이터베이스에서 조회") @ApiResponses(value ={ @@ -38,12 +42,17 @@ public class Lottery720Controller { @GetMapping("/round/{round}") public ResponseEntity getLotteryNumber( @Parameter(description = "회차", example = "1") - @PathVariable("round") Long requestRound + @PathVariable("round") String round ) { - if(requestRound == null) return ResponseEntity.badRequest().build(); + long requestRound; + try { + requestRound = Long.parseLong(round); + } catch (NumberFormatException e) { + return ResponseEntity.badRequest().build(); + } Optional roundResult - = lotteryService.getLottery720Result(requestRound); + = lotteryAIService.getLottery720Result(requestRound); if (roundResult.isEmpty()) return ResponseEntity.notFound().build(); @@ -58,4 +67,43 @@ public ResponseEntity getLotteryNumber( return ResponseEntity.ok(resultDto); } + @GetMapping("/round/{round}/store") + + @Operation(summary = "연금복권 1등 판매처 데이터 조회", description = "해당 회차 연금복권 1등 판매처 정보를 데이터베이스에서 조회") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "데이터 조회 성공", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = LotteryStoreDto.class))), + @ApiResponse(responseCode = "400", description = "잘못된 인자 값", content = @Content()), + @ApiResponse(responseCode = "404", description = "해당 회차 당첨 정보가 없음", content = @Content()) + }) + public ResponseEntity getRoundStoreList( + @Parameter(description = "회차", example = "1") + @PathVariable("round") String round + ) { + long requestRound; + try { + requestRound = Long.parseLong(round); + } catch (NumberFormatException e) { + return ResponseEntity.badRequest().build(); + } + + Optional roundResult + = lotteryAIService.getLottery720Result(requestRound); + + if (roundResult.isEmpty()) return ResponseEntity.notFound().build(); + Lottery720Entity entity = roundResult.get(); + + List storeList = new ArrayList<>(); + entity.getStoreList().forEach(entityStore -> { + LotteryStoreEntity storeEntity = entityStore.getStoreEntity(); + storeList.add(new LotteryStoreDto( + storeEntity.getId(), + storeEntity.getStoreName(), + storeEntity.getStoreAddress() + )); + } + ); + return ResponseEntity.ok(storeList); + } + } diff --git a/src/main/java/com/ohlottery/controller/LotteryAIController.java b/src/main/java/com/ohlottery/controller/LotteryAIController.java index 6fecdbe..3b10a1d 100644 --- a/src/main/java/com/ohlottery/controller/LotteryAIController.java +++ b/src/main/java/com/ohlottery/controller/LotteryAIController.java @@ -2,7 +2,7 @@ import com.ohlottery.dto.Lottery645Dto; import com.ohlottery.dto.Lottery720Dto; -import com.ohlottery.service.LotteryService; +import com.ohlottery.service.LotteryAIService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -15,29 +15,13 @@ @RequestMapping("/lottery/ai") public class LotteryAIController { - private final LotteryService lotteryService; + private final LotteryAIService lotteryAIService; @GetMapping("/predict/645/{round}") public ResponseEntity get645Predict( @PathVariable long round ) { - return ResponseEntity.ok( - new Lottery645Dto( - 0, - null, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ) - ); + return null; } @GetMapping("/statistic/645") @@ -54,15 +38,7 @@ public ResponseEntity get645Trend() { public ResponseEntity get720Predict( @PathVariable long round ) { - return ResponseEntity.ok( - new Lottery720Dto( - 0, - null, - 0, - 0, - 0 - ) - ); + return null; } @GetMapping("/statistic/720") diff --git a/src/main/java/com/ohlottery/dto/LotteryStoreDto.java b/src/main/java/com/ohlottery/dto/LotteryStoreDto.java new file mode 100644 index 0000000..df587d3 --- /dev/null +++ b/src/main/java/com/ohlottery/dto/LotteryStoreDto.java @@ -0,0 +1,21 @@ +package com.ohlottery.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +@Schema(description = "로또 판매점 정보") +public class LotteryStoreDto { + + @Schema(description = "판매처 ID", example = "1") + private long storeId; + + @Schema(description = "판매처 이름", example = "1148") + private String storeName; + + @Schema(description = "판매처 주소", example = "서울특별시 서초구 남부순환로 2423") + private String storeAddress; +} + diff --git a/src/main/java/com/ohlottery/entity/Lottery645Entity.java b/src/main/java/com/ohlottery/entity/Lottery645Entity.java index f273381..a42cb0b 100644 --- a/src/main/java/com/ohlottery/entity/Lottery645Entity.java +++ b/src/main/java/com/ohlottery/entity/Lottery645Entity.java @@ -1,9 +1,12 @@ package com.ohlottery.entity; +import com.ohlottery.entity.middle.Lottery645EntityStore; import jakarta.persistence.*; import lombok.*; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; @Entity @Getter @@ -31,4 +34,7 @@ public class Lottery645Entity { private long firstWinAmount; // 총 판매금액 private long totalSellAmount; + + @OneToMany(mappedBy = "lotteryEntity", cascade = CascadeType.ALL, orphanRemoval = true) + private final List storeList = new ArrayList<>(); } diff --git a/src/main/java/com/ohlottery/entity/Lottery645WinningEntity.java b/src/main/java/com/ohlottery/entity/Lottery645WinningEntity.java new file mode 100644 index 0000000..87ae961 --- /dev/null +++ b/src/main/java/com/ohlottery/entity/Lottery645WinningEntity.java @@ -0,0 +1,18 @@ +package com.ohlottery.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +public class Lottery645WinningEntity extends LotteryWinningEntity { + + @Enumerated(EnumType.STRING) + private WinningType type; + + public Lottery645WinningEntity(WinningType type) { + this.type = type; + } +} diff --git a/src/main/java/com/ohlottery/entity/Lottery720Entity.java b/src/main/java/com/ohlottery/entity/Lottery720Entity.java index a4dda0f..4b71d99 100644 --- a/src/main/java/com/ohlottery/entity/Lottery720Entity.java +++ b/src/main/java/com/ohlottery/entity/Lottery720Entity.java @@ -1,9 +1,12 @@ package com.ohlottery.entity; +import com.ohlottery.entity.middle.Lottery720EntityStore; import jakarta.persistence.*; import lombok.*; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; @Entity @Getter @@ -19,4 +22,7 @@ public class Lottery720Entity { private byte rankClass;// 조 번호 private int rankNo;// 당첨 번호 private int bonusNo;// 보너스 번호 + + @OneToMany(mappedBy = "lotteryEntity", cascade = CascadeType.ALL, orphanRemoval = true) + private final List storeList = new ArrayList<>(); } diff --git a/src/main/java/com/ohlottery/entity/LotteryStoreEntity.java b/src/main/java/com/ohlottery/entity/LotteryStoreEntity.java new file mode 100644 index 0000000..d194b4b --- /dev/null +++ b/src/main/java/com/ohlottery/entity/LotteryStoreEntity.java @@ -0,0 +1,38 @@ +package com.ohlottery.entity; + +import com.ohlottery.entity.middle.Lottery645EntityStore; +import com.ohlottery.entity.middle.Lottery720EntityStore; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor +public class LotteryStoreEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String storeName; + private String storeAddress; + + @OneToMany(mappedBy = "storeEntity", cascade = CascadeType.ALL, orphanRemoval = true) + private final List entity645List = new ArrayList<>(); + + @OneToMany(mappedBy = "storeEntity", cascade = CascadeType.ALL, orphanRemoval = true) + private final List entity720List = new ArrayList<>(); + + @OneToMany(mappedBy = "store", cascade = CascadeType.ALL, orphanRemoval = true) + private final List winningList = new ArrayList<>(); + + public LotteryStoreEntity(String storeName, String storeAddress) { + this.storeName = storeName; + this.storeAddress = storeAddress; + } +} + diff --git a/src/main/java/com/ohlottery/entity/LotteryWinningEntity.java b/src/main/java/com/ohlottery/entity/LotteryWinningEntity.java new file mode 100644 index 0000000..19716a2 --- /dev/null +++ b/src/main/java/com/ohlottery/entity/LotteryWinningEntity.java @@ -0,0 +1,23 @@ +package com.ohlottery.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@NoArgsConstructor +@Inheritance(strategy = InheritanceType.JOINED) +@DiscriminatorColumn +public class LotteryWinningEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + @Setter + private LotteryStoreEntity store; +} \ No newline at end of file diff --git a/src/main/java/com/ohlottery/entity/WinningType.java b/src/main/java/com/ohlottery/entity/WinningType.java new file mode 100644 index 0000000..cf95224 --- /dev/null +++ b/src/main/java/com/ohlottery/entity/WinningType.java @@ -0,0 +1,13 @@ +package com.ohlottery.entity; + +public enum WinningType { + AUTO, MANUAL; + + public static WinningType fromString(String value) { + return switch (value) { + case "자동" -> AUTO; + case "수동" -> MANUAL; + default -> null; + }; + } +} diff --git a/src/main/java/com/ohlottery/entity/middle/Lottery645EntityStore.java b/src/main/java/com/ohlottery/entity/middle/Lottery645EntityStore.java new file mode 100644 index 0000000..c567535 --- /dev/null +++ b/src/main/java/com/ohlottery/entity/middle/Lottery645EntityStore.java @@ -0,0 +1,27 @@ +package com.ohlottery.entity.middle; + +import com.ohlottery.entity.Lottery645Entity; +import com.ohlottery.entity.LotteryStoreEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Lottery645EntityStore { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "entity_id") + private Lottery645Entity lotteryEntity; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + private LotteryStoreEntity storeEntity; +} diff --git a/src/main/java/com/ohlottery/entity/middle/Lottery720EntityStore.java b/src/main/java/com/ohlottery/entity/middle/Lottery720EntityStore.java new file mode 100644 index 0000000..fc3953e --- /dev/null +++ b/src/main/java/com/ohlottery/entity/middle/Lottery720EntityStore.java @@ -0,0 +1,27 @@ +package com.ohlottery.entity.middle; + +import com.ohlottery.entity.Lottery720Entity; +import com.ohlottery.entity.LotteryStoreEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Lottery720EntityStore { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "entity_id") + Lottery720Entity lotteryEntity; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + LotteryStoreEntity storeEntity; +} diff --git a/src/main/java/com/ohlottery/repository/Lottery720Repository.java b/src/main/java/com/ohlottery/repository/Lottery720Repository.java index 5211267..f2358a7 100644 --- a/src/main/java/com/ohlottery/repository/Lottery720Repository.java +++ b/src/main/java/com/ohlottery/repository/Lottery720Repository.java @@ -7,7 +7,9 @@ @Repository public interface Lottery720Repository extends JpaRepository { + boolean existsByRound(long round); + @Query("SELECT COALESCE(MAX(l.round), 0) FROM Lottery720Entity l") int findMaxRound(); diff --git a/src/main/java/com/ohlottery/repository/LotteryStoreRepository.java b/src/main/java/com/ohlottery/repository/LotteryStoreRepository.java new file mode 100644 index 0000000..442df98 --- /dev/null +++ b/src/main/java/com/ohlottery/repository/LotteryStoreRepository.java @@ -0,0 +1,12 @@ +package com.ohlottery.repository; + +import com.ohlottery.entity.LotteryStoreEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface LotteryStoreRepository extends JpaRepository { + Optional findByStoreNameAndStoreAddress(String storeName, String storeAddress); +} diff --git a/src/main/java/com/ohlottery/scheduler/LotteryCrawlerScheduler.java b/src/main/java/com/ohlottery/scheduler/LotteryCrawlerScheduler.java index 4c015fa..909d41b 100644 --- a/src/main/java/com/ohlottery/scheduler/LotteryCrawlerScheduler.java +++ b/src/main/java/com/ohlottery/scheduler/LotteryCrawlerScheduler.java @@ -23,7 +23,8 @@ public void scheduleFetchLottery645Data() { try { int latestRound = getLatestLottery645Round(); log.info("가져온 최신 6/45 로또 회차: {}", latestRound); - scheduleRetryFetch(() -> lotteryCrawlerService.fetchLottery645Data(latestRound), "6/45", latestRound); + scheduleRetryFetch(() + -> lotteryCrawlerService.fetchLottery645Data(latestRound), "6/45", latestRound); } catch (Exception e) { log.error("fetchLottery645Data 실행 중 에러 발생", e); } @@ -35,7 +36,8 @@ public void scheduleFetchLottery720Data() { try { int latestRound = getLatestLottery720Round(); log.info("가져온 최신 720 로또 회차: {}", latestRound); - scheduleRetryFetch(() -> lotteryCrawlerService.fetchLottery720Data(latestRound), "720", latestRound); + scheduleRetryFetch(() + -> lotteryCrawlerService.fetchLottery720Data(latestRound), "720", latestRound); } catch (Exception e) { log.error("fetchLottery720Data 실행 중 에러 발생", e); } diff --git a/src/main/java/com/ohlottery/service/DHLotteryCrawlerService.java b/src/main/java/com/ohlottery/service/DHLotteryCrawlerService.java index a112480..bee4e03 100644 --- a/src/main/java/com/ohlottery/service/DHLotteryCrawlerService.java +++ b/src/main/java/com/ohlottery/service/DHLotteryCrawlerService.java @@ -3,18 +3,25 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.ohlottery.entity.Lottery645Entity; -import com.ohlottery.entity.Lottery720Entity; +import com.ohlottery.entity.*; +import com.ohlottery.entity.middle.Lottery645EntityStore; +import com.ohlottery.entity.middle.Lottery720EntityStore; import com.ohlottery.repository.Lottery645Repository; import com.ohlottery.repository.Lottery720Repository; +import com.ohlottery.repository.LotteryStoreRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.time.LocalDate; +import java.util.Optional; @Service @Slf4j @@ -24,13 +31,15 @@ public class DHLotteryCrawlerService { private final Lottery645Repository lottery645Repository; private final Lottery720Repository lottery720Repository; + private final LotteryStoreRepository storeRepository; + @Async @Transactional public void fetchAllLotteryData() { //모든 데이터가 fail이랑 없다고 뜰 때 까지 모든 데이터 긁어오기 log.info("Started fetching Lottery 645 data."); try { - for(int round=1; ; round++) { + for (int round = 1; ; round++) { if (lottery645Repository.existsByRound(round)) { log.warn("해당 회차 {} 데이터가 이미 존재함 - 저장 생략!", round); continue; @@ -38,6 +47,8 @@ public void fetchAllLotteryData() { Lottery645Entity entity = crawlLottery645Data(round); lottery645Repository.save(entity); + + fetchLottery645StoreData(round); log.info("{}회차 데이터 저장 완료!", round); } } catch (IllegalArgumentException ignored) { @@ -48,7 +59,7 @@ public void fetchAllLotteryData() { log.info("Started fetching Lottery 645 data."); try { - for(int round=1; ; round++) { + for (int round = 1; ; round++) { if (lottery720Repository.existsByRound(round)) { log.warn("해당 회차 {} 데이터가 이미 존재함 - 저장 생략!", round); continue; @@ -56,6 +67,8 @@ public void fetchAllLotteryData() { Lottery720Entity entity = crawlLottery720Data(round); lottery720Repository.save(entity); + + fetchLottery720StoreData(round); log.info("{}회차 데이터 저장 완료!", round); } } catch (IllegalArgumentException ignored) { @@ -78,12 +91,76 @@ public void fetchLottery645Data(long round) { try { Lottery645Entity entity = crawlLottery645Data(round); lottery645Repository.save(entity); + + fetchLottery645StoreData(round); + log.info("{}회차 데이터 저장 완료!", round); } catch (Exception e) { log.error("{}회차 데이터 저장 중 에러 발생: {}", round, e.getMessage(), e); } } + private void fetchLottery645StoreData(long round) throws IOException { + log.info("fetchLottery645StoreData 실행 : {}", round); + + String url = "https://dhlottery.co.kr/store.do?method=topStore&pageGubun=L645&drwNo=" + round; + + // HTML 문서를 Jsoup으로 가져오기 + Document document = Jsoup.connect(url).get(); + log.info("URL 로드 완료"); + + // 1등 배출점 테이블 선택 + Element table = document.selectFirst(".tbl_data.tbl_data_col"); + if (table == null) { + throw new IOException("1등 배출점 테이블을 찾을 수 없습니다."); + } + + Optional lotteryOptional = lottery645Repository.findById(round); + if (lotteryOptional.isEmpty()) { + log.warn("상위 엔티티 불러오기 실패"); + return; + } + Lottery645Entity lottery645 = lotteryOptional.get(); + + // 테이블의 행 데이터 추출 + Elements rows = table.select("tbody > tr"); + if (rows.size() == 1 && rows.get(0).text().contains("조회 결과가 없습니다.")) { + log.info("해당 회차 1등 배출점이 없습니다."); + log.info("fetchLottery645StoreData 완료 : {}", round); + return; + } + + log.info("1등 배출점 파싱 완료"); + for (Element row : rows) { + Elements columns = row.select("td"); + + // 데이터 파싱 + String storeName = columns.get(1).text(); + WinningType winningType = WinningType.fromString(columns.get(2).text().trim()); + String address = columns.get(3).text(); + + //Store - winning 맵핑 + Optional storeOptional = storeRepository.findByStoreNameAndStoreAddress(storeName, address); + LotteryStoreEntity storeEntity + = storeOptional.orElseGet(() -> storeRepository.save(new LotteryStoreEntity(storeName, address))); + + Lottery645WinningEntity winningEntity = new Lottery645WinningEntity(winningType); + winningEntity.setStore(storeEntity); + storeEntity.getWinningList().add(winningEntity); + + //Store - entity 맵핑 + Lottery645EntityStore middleEntity = new Lottery645EntityStore(); + middleEntity.setLotteryEntity(lottery645); + middleEntity.setStoreEntity(storeEntity); + + lottery645.getStoreList().add(middleEntity); + storeEntity.getEntity645List().add(middleEntity); + + log.info("{}, {} 저장 완료", storeName, address); + } + log.info("fetchLottery645StoreData 완료 : {}", round); + } + @Async @Transactional public void fetchLottery720Data(long round) { @@ -97,12 +174,75 @@ public void fetchLottery720Data(long round) { try { Lottery720Entity entity = crawlLottery720Data(round); lottery720Repository.save(entity); // 엔티티 저장 + + fetchLottery720StoreData(round); + log.info("회차 {} 데이터 저장 완료.", round); } catch (Exception e) { log.error("해당 회차에 대한 데이터 저장 중 에러 발생: {}", round, e); } } + private void fetchLottery720StoreData(long round) throws IOException { + log.info("fetchLottery720StoreData 실행 : {}", round); + + String url = "https://dhlottery.co.kr/store.do?method=topStore&pageGubun=L720&drwNo=" + round; + + // HTML 문서를 Jsoup으로 가져오기 + Document document = Jsoup.connect(url).get(); + log.info("URL 로드 완료"); + + // 1등 배출점 테이블 선택 + Element table = document.selectFirst(".tbl_data.tbl_data_col"); + if (table == null) { + throw new IOException("1등 배출점 테이블을 찾을 수 없습니다."); + } + + Optional lotteryOptional = lottery720Repository.findById(round); + if (lotteryOptional.isEmpty()) { + log.warn("상위 엔티티 불러오기 실패"); + return; + } + Lottery720Entity lottery720 = lotteryOptional.get(); + + // 테이블의 행 데이터 추출 + Elements rows = table.select("tbody > tr"); + if (rows.size() == 1 && rows.get(0).text().contains("조회 결과가 없습니다.")) { + log.info("해당 회차 1등 배출점이 없습니다."); + log.info("fetchLottery720StoreData 완료 : {}", round); + return; + } + + log.info("1등 배출점 파싱 완료"); + for (Element row : rows) { + Elements columns = row.select("td"); + + // 데이터 파싱 + String storeName = columns.get(1).text(); + String address = columns.get(2).text(); + + //Store - winning 맵핑 + Optional storeOptional = storeRepository.findByStoreNameAndStoreAddress(storeName, address); + LotteryStoreEntity storeEntity + = storeOptional.orElseGet(() -> storeRepository.save(new LotteryStoreEntity(storeName, address))); + + LotteryWinningEntity winningEntity = new LotteryWinningEntity(); + winningEntity.setStore(storeEntity); + storeEntity.getWinningList().add(winningEntity); + + //Store - entity 맵핑 + Lottery720EntityStore middleEntity = new Lottery720EntityStore(); + middleEntity.setLotteryEntity(lottery720); + middleEntity.setStoreEntity(storeEntity); + + lottery720.getStoreList().add(middleEntity); + storeEntity.getEntity720List().add(middleEntity); + + log.info("{}, {} 저장 완료", storeName, address); + } + log.info("fetchLottery720StoreData 완료 : {}", round); + } + private Lottery645Entity crawlLottery645Data(long round) throws Exception { //Text만 추출 String url = "https://dhlottery.co.kr/common.do?method=getLottoNumber&drwNo=" + round; diff --git a/src/main/java/com/ohlottery/service/LotteryService.java b/src/main/java/com/ohlottery/service/LotteryAIService.java similarity index 69% rename from src/main/java/com/ohlottery/service/LotteryService.java rename to src/main/java/com/ohlottery/service/LotteryAIService.java index ef064ac..47504c5 100644 --- a/src/main/java/com/ohlottery/service/LotteryService.java +++ b/src/main/java/com/ohlottery/service/LotteryAIService.java @@ -1,6 +1,7 @@ package com.ohlottery.service; import com.ohlottery.dto.Lottery645Dto; +import com.ohlottery.dto.Lottery720Dto; import com.ohlottery.entity.Lottery645Entity; import com.ohlottery.entity.Lottery720Entity; import com.ohlottery.repository.Lottery645Repository; @@ -12,7 +13,7 @@ @Service @RequiredArgsConstructor -public class LotteryService { +public class LotteryAIService { private final Lottery645Repository lottery645Repository; private final Lottery720Repository lottery720Repository; @@ -25,8 +26,20 @@ public Optional getLottery720Result(long round){ return lottery720Repository.findById(round); } - public Lottery645Dto getPredict645(long rank){ - + public Lottery645Dto getPredict645(long round){ + return null; + } + + public Lottery720Dto getPredict720(long round){ + return null; + } + + public String getTrend645(long round){ + return null; + } + + public String getTrend720(long round){ + return null; } }