From 665ac993cedd9b38aa5dd75ffbc01a5ef9ac7909 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Tue, 25 Jun 2024 00:00:46 +0900 Subject: [PATCH 01/31] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presenation/CrawlController.java | 41 ------- .../presenation/RoadCrawlController.java | 41 +++++++ .../RoadCrawlResponse.java} | 4 +- .../service/BusanCourseHandler.java | 12 -- .../service/CrawlFacadeService.java | 36 ------ .../service/DuruCourseHandler.java | 35 ------ .../application/service/DuruThemeHandler.java | 26 ----- ...andler.java => RoadBusanThemeHandler.java} | 6 +- .../service/RoadCrawlBusanCourseHandler.java | 12 ++ .../service/RoadCrawlFacadeService.java | 36 ++++++ .../service/RoadDuruCourseHandler.java | 35 ++++++ .../service/RoadDuruThemeHandler.java | 26 +++++ .../crawl/domain/constant/CycleType.java | 4 +- ...Service.java => ResponseCrawlService.java} | 2 +- ...mpl.java => ResponseCrawlServiceImpl.java} | 2 +- ...pl.java => RoadCrawlBusanServiceImpl.java} | 13 +-- .../RoadAbstractCrawlDuruService.java} | 4 +- ...uService.java => RoadCityDuruService.java} | 18 +-- ....java => RoadCourseDetailDuruService.java} | 8 +- ...ervice.java => RoadCourseDuruService.java} | 18 +-- ...e.java => RoadCourseDuruThemeService.java} | 16 +-- ...mpl.java => RoadCrawlDuruServiceImpl.java} | 47 ++++---- ...rvice.java => RoadGpxInfoDuruService.java} | 8 +- ...roperties.java => RoadEndpointConfig.java} | 7 +- .../dto/request/CourseDetailRequestDTO.java | 4 +- ...Response.java => AbstractApiResponse.java} | 2 +- ...seResponse.java => ApiCourseResponse.java} | 2 +- ...emeResponse.java => ApiThemeResponse.java} | 2 +- ...ava => RoadCrawlResponseParserHelper.java} | 2 +- .../common/dto}/ApiProperties.java | 2 +- .../service/CrawlFacadeServiceTest.java | 103 ----------------- .../domain/constant/CourseLevelTest.java | 33 ------ .../service/ApiResponseServiceImplTest.java | 97 ---------------- .../service/duru/CourseThemeServiceTest.java | 47 -------- .../service/duru/CrawlDuruServiceTest.java | 99 ----------------- .../helper/CrawlApiBuilderHelperTest.java | 86 --------------- .../helper/CrawlResponseParserHelperTest.java | 55 --------- .../service/RoadCrawlFacadeServiceTest.java | 104 ++++++++++++++++++ .../service/RoadDuruCourseHandlerTest.java} | 41 +++---- .../service/RoadDuruThemeHandlerTest.java} | 27 ++--- .../domain/constant/CycleTypeTest.java | 11 +- .../domain/constant/ProvinceTest.java | 3 +- .../duru/RoadCityDuruServiceTest.java} | 15 ++- .../RoadCourseDetailDuruServiceTest.java} | 19 ++-- .../duru/RoadCourseDuruServiceTest.java} | 19 ++-- .../duru/RoadGpxInfoDuruServiceTest.java} | 21 ++-- .../config/RoadEndpointConfigTest.java} | 14 +-- 47 files changed, 428 insertions(+), 837 deletions(-) delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/presenation/CrawlController.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java rename src/main/java/com/hubo/gillajabi/crawl/application/{dto/response/CrawlResponse.java => response/RoadCrawlResponse.java} (94%) delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/BusanCourseHandler.java delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeService.java delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandler.java delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandler.java rename src/main/java/com/hubo/gillajabi/crawl/application/service/{BusanThemeHandler.java => RoadBusanThemeHandler.java} (58%) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java rename src/main/java/com/hubo/gillajabi/crawl/domain/service/{ApiResponseService.java => ResponseCrawlService.java} (87%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/{ApiResponseServiceImpl.java => ResponseCrawlServiceImpl.java} (96%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/{CrawlBusanServiceImpl.java => RoadCrawlBusanServiceImpl.java} (65%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/{AbstarctCrawlService.java => duru/RoadAbstractCrawlDuruService.java} (51%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{CityDuruService.java => RoadCityDuruService.java} (75%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{CourseDetailDuruService.java => RoadCourseDetailDuruService.java} (93%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{CourseDuruService.java => RoadCourseDuruService.java} (77%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{CourseDuruThemeService.java => RoadCourseDuruThemeService.java} (73%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{CrawlDuruServiceImpl.java => RoadCrawlDuruServiceImpl.java} (64%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{GpxInfoDuruService.java => RoadGpxInfoDuruService.java} (92%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/{RoadProperties.java => RoadEndpointConfig.java} (79%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/{AbstractDuruResponse.java => AbstractApiResponse.java} (95%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/{DuruCourseResponse.java => ApiCourseResponse.java} (89%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/{DuruThemeResponse.java => ApiThemeResponse.java} (83%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/{CrawlResponseParserHelper.java => RoadCrawlResponseParserHelper.java} (96%) rename src/main/java/com/hubo/gillajabi/{crawl/infrastructure/config => global/common/dto}/ApiProperties.java (78%) delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeServiceTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImplTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseThemeServiceTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java delete mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlResponseParserHelperTest.java create mode 100644 src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java rename src/test/java/com/hubo/gillajabi/{crawl/application/service/DuruCourseHandlerTest.java => road/application/service/RoadDuruCourseHandlerTest.java} (68%) rename src/test/java/com/hubo/gillajabi/{crawl/application/service/DuruThemeHandlerTest.java => road/application/service/RoadDuruThemeHandlerTest.java} (58%) rename src/test/java/com/hubo/gillajabi/{crawl => road}/domain/constant/CycleTypeTest.java (72%) rename src/test/java/com/hubo/gillajabi/{crawl => road}/domain/constant/ProvinceTest.java (96%) rename src/test/java/com/hubo/gillajabi/{crawl/domain/service/duru/CityDuruServiceTest.java => road/domain/service/duru/RoadCityDuruServiceTest.java} (74%) rename src/test/java/com/hubo/gillajabi/{crawl/domain/service/duru/CourseDetailDuruServiceTest.java => road/domain/service/duru/RoadCourseDetailDuruServiceTest.java} (82%) rename src/test/java/com/hubo/gillajabi/{crawl/domain/service/duru/CourseDuruServiceTest.java => road/domain/service/duru/RoadCourseDuruServiceTest.java} (81%) rename src/test/java/com/hubo/gillajabi/{crawl/domain/service/duru/GpxInfoDuruServiceTest.java => road/domain/service/duru/RoadGpxInfoDuruServiceTest.java} (81%) rename src/test/java/com/hubo/gillajabi/{crawl/infraStructure/config/RoadPropertiesTest.java => road/infraStructure/config/RoadEndpointConfigTest.java} (74%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/CrawlController.java b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/CrawlController.java deleted file mode 100644 index 0ade1adf..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/CrawlController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.hubo.gillajabi.crawl.application.presenation; - - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import com.hubo.gillajabi.crawl.application.service.CrawlFacadeService; -import com.hubo.gillajabi.crawl.domain.constant.CityName; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/crawl") -@RequiredArgsConstructor -@Tag(name = "crawl 컨트롤러", description = "관리자 공공데이터 포털 호출 api") -public class CrawlController { - - private final CrawlFacadeService crawlFacadeService; - - @Operation(summary = "전국 길 크롤링 ", description = "만약 해당 정보가 존재한다면 생략합니다.") - @GetMapping("/courses") - public ResponseEntity startCrawlingCurse(@Valid @RequestParam CityName cityName) { - - CrawlResponse.CourseResult response = crawlFacadeService.getCourse(cityName); - - return ResponseEntity.ok().body(response); - } - - @Operation(summary = "전국 길 테마 크롤링", description = "전국 길 테마 크롤링 (ex: 남파랑길)") - @GetMapping("/themes") - public ResponseEntity startCrawlingTheme(@Valid @RequestParam CityName cityName) { - - CrawlResponse.ThemeResult response = crawlFacadeService.getTheme(cityName); - - return ResponseEntity.ok().body(response); - } -} - - diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java new file mode 100644 index 00000000..7346f6b4 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java @@ -0,0 +1,41 @@ +package com.hubo.gillajabi.crawl.application.presenation; + + +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import com.hubo.gillajabi.crawl.application.service.RoadCrawlFacadeService; +import com.hubo.gillajabi.crawl.domain.constant.CityName; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/road/crawl") +@RequiredArgsConstructor +@Tag(name = "Road crawl 컨트롤러", description = "관리자 공공데이터 포털 호출 api(길 관련)") +public class RoadCrawlController { + + private final RoadCrawlFacadeService roadCrawlFacadeService; + + @Operation(summary = "전국 길 크롤링 ", description = "만약 해당 정보가 존재한다면 생략합니다.") + @PostMapping("/courses") + public ResponseEntity startCrawlingCurse(@Valid @RequestParam CityName cityName) { + + RoadCrawlResponse.CourseResult response = roadCrawlFacadeService.getCourse(cityName); + + return ResponseEntity.ok().body(response); + } + + @Operation(summary = "전국 길 테마 크롤링", description = "전국 길 테마 크롤링 (ex: 남파랑길)") + @PostMapping("/themes") + public ResponseEntity startCrawlingTheme(@Valid @RequestParam CityName cityName) { + + RoadCrawlResponse.ThemeResult response = roadCrawlFacadeService.getTheme(cityName); + + return ResponseEntity.ok().body(response); + } +} + + diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/dto/response/CrawlResponse.java b/src/main/java/com/hubo/gillajabi/crawl/application/response/RoadCrawlResponse.java similarity index 94% rename from src/main/java/com/hubo/gillajabi/crawl/application/dto/response/CrawlResponse.java rename to src/main/java/com/hubo/gillajabi/crawl/application/response/RoadCrawlResponse.java index c2a02226..d652124f 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/dto/response/CrawlResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/application/response/RoadCrawlResponse.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.application.dto.response; +package com.hubo.gillajabi.crawl.application.response; import com.hubo.gillajabi.crawl.domain.entity.*; import io.swagger.v3.oas.annotations.media.Schema; @@ -11,7 +11,7 @@ @Getter @Setter -public class CrawlResponse { +public class RoadCrawlResponse { @Getter @Setter diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/BusanCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/BusanCourseHandler.java deleted file mode 100644 index 2f369a1c..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/BusanCourseHandler.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.hubo.gillajabi.crawl.application.service; - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import org.springframework.stereotype.Service; - -@Service -public class BusanCourseHandler { - - public CrawlResponse.CourseResult handle() { - return null; - } -} diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeService.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeService.java deleted file mode 100644 index 344f6deb..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.hubo.gillajabi.crawl.application.service; - - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import com.hubo.gillajabi.crawl.domain.constant.CityName; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - - -@Service -@RequiredArgsConstructor -public class CrawlFacadeService { - - private final DuruCourseHandler duruCourseHandler; - private final BusanCourseHandler busanCourseHandler; - private final DuruThemeHandler duruThemeHandler; - private final BusanThemeHandler busanThemeHandler; - - public CrawlResponse.CourseResult getCourse(final CityName cityName) { - return switch (cityName) { - case DURU -> duruCourseHandler.handle(); - case BUSAN -> busanCourseHandler.handle(); - }; - } - - public CrawlResponse.ThemeResult getTheme(final CityName cityName) { - return switch (cityName) { - case DURU -> duruThemeHandler.handle(); - case BUSAN -> busanThemeHandler.handle(); - }; - } -} - - - - diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandler.java deleted file mode 100644 index b013f0e7..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandler.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.hubo.gillajabi.crawl.application.service; - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import com.hubo.gillajabi.crawl.domain.entity.City; -import com.hubo.gillajabi.crawl.domain.entity.Course; -import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; -import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; -import com.hubo.gillajabi.crawl.domain.service.duru.*; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class DuruCourseHandler { - - private final CrawlDuruServiceImpl duruCrawlService; - private final CityDuruService cityService; - private final CourseDuruService courseDuruService; - private final CourseDetailDuruService courseDetailDuruService; - private final GpxInfoDuruService gpxInfoDuruService; - - public CrawlResponse.CourseResult handle() { - List rawCourses = duruCrawlService.crawlCourse(); - List cities = cityService.saveCity(rawCourses); - List courses = courseDuruService.saveDuruCourse(rawCourses, cities); - List courseDetails = courseDetailDuruService.saveDuruCourseDetail(rawCourses, courses); - List gpxInfos = gpxInfoDuruService.saveGpxInfo(courseDetails); - - return CrawlResponse.CourseResult.of(cities, courses, courseDetails, gpxInfos); - - } -} diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandler.java deleted file mode 100644 index 542e909b..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.hubo.gillajabi.crawl.application.service; - - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.CourseDuruThemeService; -import com.hubo.gillajabi.crawl.domain.service.duru.CrawlDuruServiceImpl; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class DuruThemeHandler { - - private final CrawlDuruServiceImpl duruCrawlService; - private final CourseDuruThemeService courseDuruThemeService; - - public CrawlResponse.ThemeResult handle() { - List responseItems = duruCrawlService.crawlTheme(); - List themes = courseDuruThemeService.saveDuruTheme(responseItems); - return CrawlResponse.ThemeResult.from(themes); - } -} diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/BusanThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java similarity index 58% rename from src/main/java/com/hubo/gillajabi/crawl/application/service/BusanThemeHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java index 8ab81225..fe00c834 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/BusanThemeHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java @@ -1,14 +1,14 @@ package com.hubo.gillajabi.crawl.application.service; -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor -public class BusanThemeHandler { +public class RoadBusanThemeHandler { - public CrawlResponse.ThemeResult handle() { + public RoadCrawlResponse.ThemeResult handle() { return null; } } diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java new file mode 100644 index 00000000..fc8b4c61 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java @@ -0,0 +1,12 @@ +package com.hubo.gillajabi.crawl.application.service; + +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import org.springframework.stereotype.Service; + +@Service +public class RoadCrawlBusanCourseHandler { + + public RoadCrawlResponse.CourseResult handle() { + return null; + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java new file mode 100644 index 00000000..31091c41 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java @@ -0,0 +1,36 @@ +package com.hubo.gillajabi.crawl.application.service; + + +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import com.hubo.gillajabi.crawl.domain.constant.CityName; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + + +@Service +@RequiredArgsConstructor +public class RoadCrawlFacadeService { + + private final RoadDuruCourseHandler roadDuruCourseHandler; + private final RoadCrawlBusanCourseHandler roadCrawlBusanCourseHandler; + private final RoadDuruThemeHandler roadDuruThemeHandler; + private final RoadBusanThemeHandler roadBusanThemeHandler; + + public RoadCrawlResponse.CourseResult getCourse(final CityName cityName) { + return switch (cityName) { + case DURU -> roadDuruCourseHandler.handle(); + case BUSAN -> roadCrawlBusanCourseHandler.handle(); + }; + } + + public RoadCrawlResponse.ThemeResult getTheme(final CityName cityName) { + return switch (cityName) { + case DURU -> roadDuruThemeHandler.handle(); + case BUSAN -> roadBusanThemeHandler.handle(); + }; + } +} + + + + diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java new file mode 100644 index 00000000..8ba918e0 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java @@ -0,0 +1,35 @@ +package com.hubo.gillajabi.crawl.application.service; + +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import com.hubo.gillajabi.crawl.domain.entity.City; +import com.hubo.gillajabi.crawl.domain.entity.Course; +import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; +import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; +import com.hubo.gillajabi.crawl.domain.service.duru.*; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class RoadDuruCourseHandler { + + private final RoadCrawlDuruServiceImpl duruCrawlService; + private final RoadCityDuruService cityService; + private final RoadCourseDuruService roadCourseDuruService; + private final RoadCourseDetailDuruService roadCourseDetailDuruService; + private final RoadGpxInfoDuruService roadGpxInfoDuruService; + + public RoadCrawlResponse.CourseResult handle() { + List rawCourses = duruCrawlService.crawlCourse(); + List cities = cityService.saveCity(rawCourses); + List courses = roadCourseDuruService.saveDuruCourse(rawCourses, cities); + List courseDetails = roadCourseDetailDuruService.saveDuruCourseDetail(rawCourses, courses); + List gpxInfos = roadGpxInfoDuruService.saveGpxInfo(courseDetails); + + return RoadCrawlResponse.CourseResult.of(cities, courses, courseDetails, gpxInfos); + + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java new file mode 100644 index 00000000..af3f27cb --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java @@ -0,0 +1,26 @@ +package com.hubo.gillajabi.crawl.application.service; + + +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruThemeService; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCrawlDuruServiceImpl; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class RoadDuruThemeHandler { + + private final RoadCrawlDuruServiceImpl duruCrawlService; + private final RoadCourseDuruThemeService roadCourseDuruThemeService; + + public RoadCrawlResponse.ThemeResult handle() { + List responseItems = duruCrawlService.crawlTheme(); + List themes = roadCourseDuruThemeService.saveDuruTheme(responseItems); + return RoadCrawlResponse.ThemeResult.from(themes); + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CycleType.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CycleType.java index 47d6e3bb..96c7fd53 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CycleType.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CycleType.java @@ -1,11 +1,11 @@ package com.hubo.gillajabi.crawl.domain.constant; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; public enum CycleType { CYCLE, SINGLE; - public static CycleType fromValue(DuruCourseResponse.Course course) { + public static CycleType fromValue(ApiCourseResponse.Course course) { return switch (course.getCrsCycle()) { case "순환형" -> CYCLE; case "비순환형" -> SINGLE; diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java similarity index 87% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java index 34cf9957..df9a8798 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java @@ -5,7 +5,7 @@ import java.net.URI; import java.util.Optional; -public interface ApiResponseService { +public interface ResponseCrawlService { OptionalfindByRequestUrl(String string); String fetchApiResponse(URI uri); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java similarity index 96% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImpl.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java index 0414f1c0..0219cc80 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java @@ -15,7 +15,7 @@ @Transactional @RequiredArgsConstructor @Slf4j -public class ApiResponseServiceImpl implements ApiResponseService { +public class ResponseCrawlServiceImpl implements ResponseCrawlService { private final CrawlApiResponseRepository crawlApiResponseRepository; private final RestTemplate restTemplate; diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/CrawlBusanServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java similarity index 65% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/CrawlBusanServiceImpl.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java index 25e44cbf..607c60a4 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/CrawlBusanServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java @@ -1,8 +1,7 @@ package com.hubo.gillajabi.crawl.domain.service.busan; ; -import com.hubo.gillajabi.crawl.domain.service.AbstarctCrawlService; -import com.hubo.gillajabi.crawl.infrastructure.config.RoadProperties; -import com.hubo.gillajabi.crawl.infrastructure.config.ApiProperties; +import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; +import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.domain.constant.CityName; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; @@ -12,27 +11,25 @@ @Service @RequiredArgsConstructor -public class CrawlBusanServiceImpl extends AbstarctCrawlService { +public class RoadCrawlBusanServiceImpl { - private final RoadProperties roadProperties; + private final RoadEndpointConfig roadEndpointConfig; private ApiProperties busanApiProperties; @PostConstruct private void init() { - this.busanApiProperties = roadProperties.getEndpoint(CityName.BUSAN); + this.busanApiProperties = roadEndpointConfig.getEndpoint(CityName.BUSAN); if (this.busanApiProperties == null) { throw new IllegalStateException("BUSAN Crawl Strategy 가 초기화 되지 않았습니다."); } } - @Override public List crawlCourse() { return List.of("Busan Course 1", "Busan Course 2", "Busan Course 3"); } - @Override public List crawlTheme(){ return List.of("Busan Theme 1", "Busan Theme 2", "Busan Theme 3"); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/AbstarctCrawlService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java similarity index 51% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/AbstarctCrawlService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java index 08dcb94a..c908b33f 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/AbstarctCrawlService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java @@ -1,8 +1,8 @@ -package com.hubo.gillajabi.crawl.domain.service; +package com.hubo.gillajabi.crawl.domain.service.duru; import java.util.List; -public abstract class AbstarctCrawlService { +public abstract class RoadAbstractCrawlDuruService { public abstract List crawlCourse(); public abstract List crawlTheme(); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java similarity index 75% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java index 208525e4..cdd3612b 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java @@ -4,9 +4,9 @@ import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; -import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlResponseParserHelper; +import com.hubo.gillajabi.crawl.infrastructure.util.helper.RoadCrawlResponseParserHelper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -19,19 +19,19 @@ @Transactional @RequiredArgsConstructor @Slf4j -public class CityDuruService { +public class RoadCityDuruService { private final CityRepository cityRepository; - public List saveCity(final List responseItems) { + public List saveCity(final List responseItems) { List cities = new ArrayList<>(); - for (DuruCourseResponse.Course item : responseItems) { + for (ApiCourseResponse.Course item : responseItems) { processCourseItem(cities, item); } return cities; } - private void processCourseItem(final List cities, final DuruCourseResponse.Course item) { + private void processCourseItem(final List cities, final ApiCourseResponse.Course item) { try { final CityRequestDTO cityRequestDTO = createCityRequestDTOFromCourseItem(item); final City city = createOrFindCity(cityRequestDTO); @@ -41,10 +41,10 @@ private void processCourseItem(final List cities, final DuruCourseResponse } } - private CityRequestDTO createCityRequestDTOFromCourseItem(final DuruCourseResponse.Course item) { - final String provinceName = CrawlResponseParserHelper.parseDuruResponseByProvince(item.getSigun()); + private CityRequestDTO createCityRequestDTOFromCourseItem(final ApiCourseResponse.Course item) { + final String provinceName = RoadCrawlResponseParserHelper.parseDuruResponseByProvince(item.getSigun()); final Province province = Province.fromValue(provinceName); - final String cityName = CrawlResponseParserHelper.parseDuruResponseByCity(item.getSigun()); + final String cityName = RoadCrawlResponseParserHelper.parseDuruResponseByCity(item.getSigun()); return CityRequestDTO.of(cityName, province); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java similarity index 93% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java index be8fdcbe..68e4824e 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java @@ -4,7 +4,7 @@ import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseDetailRepository; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; import lombok.RequiredArgsConstructor; @@ -19,7 +19,7 @@ @Service @Transactional @RequiredArgsConstructor -public class CourseDetailDuruService { +public class RoadCourseDetailDuruService { private final CourseDetailRepository courseDetailRepository; private final CourseRepository courseRepository; @@ -27,7 +27,7 @@ public class CourseDetailDuruService { private static final Pattern startPattern = Pattern.compile("(?:- )?시점(?:: | :| ) (.*?)(?:
|\\s)(?:교통편\\)|\uAD50\uD1B5\uD3B8\\)) (.*?)(?:
|\\s)"); private static final Pattern endPattern = Pattern.compile("(?:- )?종점(?:: | :| ) (.*?)(?:
|\\s)(?:교통편\\)|\uAD50\uD1B5\uD3B8\\)) (.*?)(?:
|\\s)"); - public List saveDuruCourseDetail(final List responseItems, final List courses) { + public List saveDuruCourseDetail(final List responseItems, final List courses) { List courseDetails = new ArrayList<>(); responseItems.forEach(item -> { final Course course = findCourseByName(courses, item.getCrsKorNm()); @@ -40,7 +40,7 @@ public List saveDuruCourseDetail(final List saveDuruCourse(final List responseItems, final List cities) { + public List saveDuruCourse(final List responseItems, final List cities) { List courses = new ArrayList<>(); responseItems.forEach(item -> courses.add(processCourseItem(item, cities))); return courses; } - private Course processCourseItem(DuruCourseResponse.Course item, List cities) { + private Course processCourseItem(ApiCourseResponse.Course item, List cities) { City city = findCity(item, cities); CourseTheme courseTheme = findCourseTheme(item); CourseRequestDTO courseRequestDTO = CourseRequestDTO.of(item, city, courseTheme); @@ -40,10 +40,10 @@ private Course processCourseItem(DuruCourseResponse.Course item, List citi return createOrUpdateCourse(courseRequestDTO, existingCourse); } - private City findCity(final DuruCourseResponse.Course item, final List cities) { - final String provinceName = CrawlResponseParserHelper.parseDuruResponseByProvince(item.getSigun()); + private City findCity(final ApiCourseResponse.Course item, final List cities) { + final String provinceName = RoadCrawlResponseParserHelper.parseDuruResponseByProvince(item.getSigun()); final Province province = Province.fromValue(provinceName); - final String cityName = CrawlResponseParserHelper.parseDuruResponseByCity(item.getSigun()); + final String cityName = RoadCrawlResponseParserHelper.parseDuruResponseByCity(item.getSigun()); return cities.stream() .filter(c -> c.getName().equals(cityName) && c.getProvince().equals(province)) @@ -51,7 +51,7 @@ private City findCity(final DuruCourseResponse.Course item, final List cit .orElseThrow(() -> new IllegalArgumentException("City 정보가 없습니다.")); } - private CourseTheme findCourseTheme(final DuruCourseResponse.Course item) { + private CourseTheme findCourseTheme(final ApiCourseResponse.Course item) { final String courseName = item.getCrsKorNm().split(" ")[0]; return courseThemeRepository.findByName(courseName) .orElseThrow(() -> new IllegalArgumentException("CourseTheme 정보가 없습니다.")); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruThemeService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java similarity index 73% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruThemeService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java index 455728e4..ddac4225 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruThemeService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java @@ -2,7 +2,7 @@ import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -14,38 +14,38 @@ @Service @RequiredArgsConstructor @Transactional -public class CourseDuruThemeService { +public class RoadCourseDuruThemeService { private final CourseThemeRepository courseThemeRepository; - public List saveDuruTheme(List items) { + public List saveDuruTheme(List items) { List courseThemes = createOrUpdateCourseThemes(items); courseThemeRepository.saveAll(courseThemes); return courseThemes; } - private List createOrUpdateCourseThemes(List items) { + private List createOrUpdateCourseThemes(List items) { List courseThemes = new ArrayList<>(); - for (DuruThemeResponse.Theme item : items) { + for (ApiThemeResponse.Theme item : items) { CourseTheme courseTheme = findOrCreateCourseTheme(item); courseThemes.add(courseTheme); } return courseThemes; } - private CourseTheme findOrCreateCourseTheme(DuruThemeResponse.Theme item) { + private CourseTheme findOrCreateCourseTheme(ApiThemeResponse.Theme item) { return courseThemeRepository.findByName(item.getThemeNm()) .map(existingTheme -> updateExistingCourseTheme(existingTheme, item)) .orElseGet(() -> createNewCourseTheme(item)); } - private CourseTheme updateExistingCourseTheme(CourseTheme existingTheme, DuruThemeResponse.Theme item) { + private CourseTheme updateExistingCourseTheme(CourseTheme existingTheme, ApiThemeResponse.Theme item) { existingTheme.update(item.getThemedescs(), item.getLinemsg()); return existingTheme; } - private CourseTheme createNewCourseTheme(DuruThemeResponse.Theme item) { + private CourseTheme createNewCourseTheme(ApiThemeResponse.Theme item) { CourseThemeRequestDTO requestDTO = CourseThemeRequestDTO.from(item); return CourseTheme.createCourseTheme(requestDTO); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java similarity index 64% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceImpl.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java index ffa0ce69..389daef8 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java @@ -4,14 +4,13 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.hubo.gillajabi.crawl.domain.constant.CityName; -import com.hubo.gillajabi.crawl.domain.service.AbstarctCrawlService; -import com.hubo.gillajabi.crawl.domain.service.ApiResponseService; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractDuruResponse; +import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractApiResponse; import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; -import com.hubo.gillajabi.crawl.infrastructure.config.RoadProperties; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; -import com.hubo.gillajabi.crawl.infrastructure.config.ApiProperties; +import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; +import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import jakarta.annotation.PostConstruct; @@ -27,13 +26,13 @@ @Service @RequiredArgsConstructor @Slf4j -public class CrawlDuruServiceImpl extends AbstarctCrawlService { +public class RoadCrawlDuruServiceImpl extends RoadAbstractCrawlDuruService { - private final RoadProperties roadProperties; + private final RoadEndpointConfig roadEndpointConfig; private final CrawlApiBuilderHelper crawlApiBuilderHelper; - private final ApiResponseService apiResponseService; + private final ResponseCrawlService responseCrawlService; - private ApiProperties duruApiProperties; + private static ApiProperties duruApiProperties; private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -41,24 +40,24 @@ public class CrawlDuruServiceImpl extends AbstarctCrawlService { @PostConstruct private void init() { - this.duruApiProperties = roadProperties.getEndpoint(CityName.DURU); + this.duruApiProperties = roadEndpointConfig.getEndpoint(CityName.DURU); validateDuruApiProperties(); } private void validateDuruApiProperties() { if (this.duruApiProperties == null) { - throw new IllegalStateException("DURU Crawl Strategy 가 초기화 되지 않았습니다."); + throw new IllegalStateException("DURU Crawl Service가 초기화 되지 않았습니다."); } } @Override - public List crawlCourse() { + public List crawlCourse() { return crawlItems(this::crawlCoursePage); } @Override - public List crawlTheme() { - List themes = crawlItems(this::crawlThemePage); + public List crawlTheme() { + List themes = crawlItems(this::crawlThemePage); themes.forEach(theme -> theme.setThemedescs(Jsoup.parse(theme.getThemedescs()).text())); return themes; } @@ -82,29 +81,29 @@ private List crawlItems(final CrawlPageFunction crawlPageFunction){ return allItems; } - private List getItems(AbstractDuruResponse.Body body) { + private List getItems(AbstractApiResponse.Body body) { if (body == null || body.getItems() == null || body.getItems().getItem() == null) { return new ArrayList<>(); } return body.getItems().getItem(); } - private List crawlCoursePage(final int pageNo) throws JsonProcessingException { - DuruCourseResponse.Body body = - crawlPage(pageNo, "courseList", DuruCourseResponse.class).getResponse().getBody(); + private List crawlCoursePage(final int pageNo) throws JsonProcessingException { + ApiCourseResponse.Body body = + crawlPage(pageNo, "courseList", ApiCourseResponse.class).getResponse().getBody(); return getItems(body); } - private List crawlThemePage(final int pageNo) throws JsonProcessingException { - DuruThemeResponse.Body body = - crawlPage(pageNo, "routeList", DuruThemeResponse.class).getResponse().getBody(); + private List crawlThemePage(final int pageNo) throws JsonProcessingException { + ApiThemeResponse.Body body = + crawlPage(pageNo, "routeList", ApiThemeResponse.class).getResponse().getBody(); return getItems(body); } private T crawlPage(final int pageNo, final String endpoint, Class responseType) throws JsonProcessingException { final URI uri = buildUri(endpoint, pageNo); - final String response = apiResponseService.fetchApiResponse(uri); + final String response = responseCrawlService.fetchApiResponse(uri); objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true); final T parsedResponse = objectMapper.readValue(response, responseType); crawlApiBuilderHelper.validateResponse(parsedResponse); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java similarity index 92% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java index c3f93af4..727a66e3 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; -import com.hubo.gillajabi.crawl.domain.service.ApiResponseService; +import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; @@ -23,10 +23,10 @@ @Transactional @RequiredArgsConstructor @Slf4j -public class GpxInfoDuruService { +public class RoadGpxInfoDuruService { private final GpxInfoRepository gpxInfoRepository; - private final ApiResponseService apiResponseService; + private final ResponseCrawlService responseCrawlService; private static final XmlMapper xmlMapper = new XmlMapper(); private static final ObjectMapper jsonMapper = new ObjectMapper(); @@ -63,7 +63,7 @@ private boolean shouldSkip(String path) { private DuruGpxResponse fetchGpxResponse(String gpxUrl) throws IOException { URI uri = URI.create(gpxUrl); - String response = apiResponseService.fetchApiResponse(uri); + String response = responseCrawlService.fetchApiResponse(uri); return xmlMapper.readValue(response, DuruGpxResponse.class); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadProperties.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java similarity index 79% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadProperties.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java index 188a822f..1c155732 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadProperties.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java @@ -1,12 +1,13 @@ package com.hubo.gillajabi.crawl.infrastructure.config; +import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.domain.constant.CityName; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; -import java.util.HashMap; +import java.util.EnumMap; import java.util.Map; @@ -14,9 +15,9 @@ @ConfigurationProperties(prefix = "road") @Slf4j @Getter -public class RoadProperties { +public class RoadEndpointConfig { - private final Map roadEndpoints = new HashMap<>(); + private final Map roadEndpoints = new EnumMap<>(CityName.class); public ApiProperties getEndpoint(CityName cityName) { return roadEndpoints.get(cityName); diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java index 6d392ebc..f1b5b5c5 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java @@ -1,7 +1,7 @@ package com.hubo.gillajabi.crawl.infrastructure.dto.request; import com.hubo.gillajabi.crawl.domain.constant.CycleType; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import lombok.*; @Getter @@ -22,7 +22,7 @@ public class CourseDetailRequestDTO { private CycleType cycleType; - public static CourseDetailRequestDTO of(final DuruCourseResponse.Course item, final String startPoint, final String endPoint, + public static CourseDetailRequestDTO of(final ApiCourseResponse.Course item, final String startPoint, final String endPoint, final String startPointTransport, final String endPointTransport) { return new CourseDetailRequestDTO( item.getCrsKorNm(), diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractDuruResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java similarity index 95% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractDuruResponse.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java index 4b3b2468..1bb65f6d 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractDuruResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java @@ -9,7 +9,7 @@ @Getter @Setter -public class AbstractDuruResponse implements ValidatableResponse{ +public class AbstractApiResponse implements ValidatableResponse{ private Response response; diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruCourseResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiCourseResponse.java similarity index 89% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruCourseResponse.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiCourseResponse.java index f7464c9f..c9e2fa06 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruCourseResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiCourseResponse.java @@ -5,7 +5,7 @@ @Getter @Setter -public class DuruCourseResponse extends AbstractDuruResponse { +public class ApiCourseResponse extends AbstractApiResponse { @Getter @Setter diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruThemeResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiThemeResponse.java similarity index 83% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruThemeResponse.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiThemeResponse.java index 3b247328..624e2171 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruThemeResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiThemeResponse.java @@ -5,7 +5,7 @@ @Getter @Setter -public class DuruThemeResponse extends AbstractDuruResponse { +public class ApiThemeResponse extends AbstractApiResponse { @Getter @Setter diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlResponseParserHelper.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/RoadCrawlResponseParserHelper.java similarity index 96% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlResponseParserHelper.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/RoadCrawlResponseParserHelper.java index 650c1def..159914f4 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlResponseParserHelper.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/RoadCrawlResponseParserHelper.java @@ -1,6 +1,6 @@ package com.hubo.gillajabi.crawl.infrastructure.util.helper; -public class CrawlResponseParserHelper { +public class RoadCrawlResponseParserHelper { /** diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/ApiProperties.java b/src/main/java/com/hubo/gillajabi/global/common/dto/ApiProperties.java similarity index 78% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/ApiProperties.java rename to src/main/java/com/hubo/gillajabi/global/common/dto/ApiProperties.java index 96eb9818..a43afa44 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/ApiProperties.java +++ b/src/main/java/com/hubo/gillajabi/global/common/dto/ApiProperties.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.infrastructure.config; +package com.hubo.gillajabi.global.common.dto; import lombok.Getter; import lombok.Setter; diff --git a/src/test/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeServiceTest.java deleted file mode 100644 index dfa2cb6e..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/application/service/CrawlFacadeServiceTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.hubo.gillajabi.crawl.application.service; - -import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; - -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; -import com.hubo.gillajabi.crawl.domain.constant.CityName; -import com.navercorp.fixturemonkey.FixtureMonkey; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -@ExtendWith(SpringExtension.class) -public class CrawlFacadeServiceTest { - - @Mock - private DuruCourseHandler duruCourseHandler; - - @Mock - private BusanCourseHandler busanCourseHandler; - - @Mock - private DuruThemeHandler duruThemeHandler; - - @Mock - private BusanThemeHandler busanThemeHandler; - - @InjectMocks - private CrawlFacadeService crawlFacadeService; - - private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); - - @Test - @DisplayName("두루 코스를 제대로 호출") - public void testGetDuruCourse() { - // given - CrawlResponse.CourseResult duruCourseResult = fixtureMonkey.giveMeBuilder(CrawlResponse.CourseResult.class) - .sample(); - - when(duruCourseHandler.handle()).thenReturn(duruCourseResult); - - // when - assertEquals(duruCourseResult, crawlFacadeService.getCourse(CityName.DURU)); - - // then - verify(duruCourseHandler).handle(); - verifyNoMoreInteractions(duruThemeHandler, busanCourseHandler, busanThemeHandler); - } - - @Test - @DisplayName("부산 코스를 제대로 호출") - public void testGetBusanCourse() { - // given - CrawlResponse.CourseResult busanCourseResult = fixtureMonkey.giveMeBuilder(CrawlResponse.CourseResult.class) - .sample(); - - when(busanCourseHandler.handle()).thenReturn(busanCourseResult); - - // when - assertEquals(busanCourseResult, crawlFacadeService.getCourse(CityName.BUSAN)); - - // then - verify(busanCourseHandler).handle(); - verifyNoMoreInteractions(duruCourseHandler, duruThemeHandler, busanThemeHandler); - } - - @Test - @DisplayName("두루 테마를 제대로 호출") - public void testGetDuruTheme() { - // given - CrawlResponse.ThemeResult duruThemeResult = fixtureMonkey.giveMeBuilder(CrawlResponse.ThemeResult.class) - .sample(); - - when(duruThemeHandler.handle()).thenReturn(duruThemeResult); - - // when - assertEquals(duruThemeResult, crawlFacadeService.getTheme(CityName.DURU)); - - // then - verify(duruThemeHandler).handle(); - verifyNoMoreInteractions(duruCourseHandler, busanCourseHandler, busanThemeHandler); - } - - @Test - @DisplayName("부산 테마를 제대로 호출") - public void testGetBusanTheme() { - // given - CrawlResponse.ThemeResult busanThemeResult = fixtureMonkey.giveMeBuilder(CrawlResponse.ThemeResult.class) - .sample(); - - when(busanThemeHandler.handle()).thenReturn(busanThemeResult); - - // when - assertEquals(busanThemeResult, crawlFacadeService.getTheme(CityName.BUSAN)); - - // then - verify(busanThemeHandler).handle(); - verifyNoMoreInteractions(duruCourseHandler, duruThemeHandler, busanCourseHandler); - } -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java deleted file mode 100644 index 7b2acc0a..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.hubo.gillajabi.crawl.domain.constant; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -class CourseLevelTest { - - @Test - @DisplayName("레벨 1은 LOW 반환") - void 두루누비_level_1일_경우() { - assertEquals(CourseLevel.LOW, CourseLevel.fromValue("1")); - } - - @Test - @DisplayName("레벨 2은 MIDDLE 반환") - void 두루누비_level_2일_경우() { - assertEquals(CourseLevel.MIDDLE, CourseLevel.fromValue("2")); - } - - @Test - @DisplayName("레벨 3은 HIGH 반환") - void 두루누비_level_3일_경우() { - assertEquals(CourseLevel.HIGH, CourseLevel.fromValue("3")); - } - - @Test - @DisplayName("잘못된 레벨 값 예외 발생") - void 두루누비_level이_잘못된_값일_경우() { - Exception exception = assertThrows(IllegalArgumentException.class, () -> CourseLevel.fromValue("4")); - assertEquals("잘못된 레벨 값 : 4", exception.getMessage()); - } -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImplTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImplTest.java deleted file mode 100644 index 77fa2b62..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/ApiResponseServiceImplTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.hubo.gillajabi.crawl.domain.service; - -import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; - -import java.net.URI; -import java.util.Optional; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.web.client.RestTemplate; - -import com.hubo.gillajabi.crawl.domain.entity.CrawlApiResponse; -import com.hubo.gillajabi.crawl.infrastructure.persistence.CrawlApiResponseRepository; - -@ExtendWith(MockitoExtension.class) -public class ApiResponseServiceImplTest { - - @Mock - private CrawlApiResponseRepository crawlApiResponseRepository; - - @Mock - private RestTemplate restTemplate; - - @InjectMocks - private ApiResponseServiceImpl apiResponseServiceImpl; - - @Test - @DisplayName("URI를 호출하여 API 응답을 가져온다") - public void uri를_호출에_성공한다() throws Exception { - // Given - String apiUrl = "http://test.com"; - String response = "response"; - URI uri = new URI(apiUrl); - - when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.empty()); - when(restTemplate.getForObject(uri, String.class)).thenReturn(response); - - // When - String result = apiResponseServiceImpl.fetchApiResponse(uri); - - // Then - assertEquals(response, result); - - ArgumentCaptor captor = ArgumentCaptor.forClass(CrawlApiResponse.class); - verify(crawlApiResponseRepository, times(1)).save(captor.capture()); - CrawlApiResponse captured = captor.getValue(); - - assertEquals(apiUrl, captured.getRequestUrl()); - assertEquals(response, captured.getResponse()); - } - - @Test - @DisplayName("캐시된 응답이 있을 경우, 캐시된 응답을 반환한다") - public void 캐시된_응답이_있을_경우_캐시된_응답을_반환_성공() throws Exception { - // Given - String apiUrl = "http://test.com"; - String cachedResponse = "cached response"; - URI uri = new URI(apiUrl); - - when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.of( - CrawlApiResponse.builder().requestUrl(apiUrl).response(cachedResponse).build() - )); - - // When - String result = apiResponseServiceImpl.fetchApiResponse(uri); - - // Then - assertEquals(cachedResponse, result); - verify(crawlApiResponseRepository, never()).save(any(CrawlApiResponse.class)); - } - - @Test - @DisplayName("잘못된 uri일 경우 에러가 발생한다") - public void 잘못된_uri일_경우_에러가_발생한다() throws Exception { - // Given - String apiUrl = "http://test.com"; - URI uri = new URI(apiUrl); - - when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.empty()); - when(restTemplate.getForObject(uri, String.class)).thenThrow(new RuntimeException()); - - // When / Then - RuntimeException exception = assertThrows(RuntimeException.class, () -> { - apiResponseServiceImpl.fetchApiResponse(uri); - }); - - assertEquals("API 응답을 가져오는 중 문제가 발생했습니다.", exception.getMessage()); - verify(crawlApiResponseRepository, never()).save(any(CrawlApiResponse.class)); - } - -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseThemeServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseThemeServiceTest.java deleted file mode 100644 index 3414e798..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseThemeServiceTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; - - -import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; -import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; -import com.navercorp.fixturemonkey.FixtureMonkey; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@ExtendWith(MockitoExtension.class) -class CourseThemeServiceTest { - - @Mock - private CourseThemeRepository courseThemeRepository; - - @InjectMocks - private CourseDuruThemeService courseDuruThemeService; - - private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); - - @Test - @DisplayName("테마를 저장한다") - public void 테마를_저장한다() { - // given - List items = new ArrayList<>(); - items.add(fixtureMonkey.giveMeOne(DuruThemeResponse.Theme.class)); - - // when - List courseThemes = courseDuruThemeService.saveDuruTheme(items); - - // then - assertEquals(1, courseThemes.size()); - - } - - -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceTest.java deleted file mode 100644 index 6415ffc5..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CrawlDuruServiceTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; - -import com.hubo.gillajabi.crawl.domain.service.ApiResponseService; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; -import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class CrawlDuruServiceTest { - - @Mock - private ApiResponseService apiResponseService; - - @Mock - private CrawlApiBuilderHelper crawlApiBuilderHelper; - - @InjectMocks - private CrawlDuruServiceImpl crawlDuruService; - - private String readJsonFile(String path) throws IOException { - Path basePath = Paths.get("src", "test", "resources"); - Path fullPath = basePath.resolve(path); - return Files.readString(fullPath, StandardCharsets.UTF_8); - } - - @Test - @DisplayName("두루누비 코스 크롤링 테스트") - void testCrawlCourse() throws URISyntaxException, IOException { - // given - makeCrawlCourseMock(); - - // when - List courses = crawlDuruService.crawlCourse(); - - // then - assertEquals(1, courses.size()); - assertEquals("서해랑길 53코스", courses.get(0).getCrsKorNm()); - } - - private void makeCrawlCourseMock() throws URISyntaxException, IOException { - URI uriCoursePage1 = new URI("http://example.com/api/courses?page=1"); - URI uriCoursePage2 = new URI("http://example.com/api/courses?page=2"); - - when(crawlApiBuilderHelper.buildUri(eq("courseList"), any(), eq(1), eq(100))).thenReturn(uriCoursePage1); - when(crawlApiBuilderHelper.buildUri(eq("courseList"), any(), eq(2), eq(100))).thenReturn(uriCoursePage2); - - String courseResponsePage1 = readJsonFile("mockedResponses/courseDuruResponsePage1.json"); - String courseResponsePage2 = readJsonFile("mockedResponses/courseDuruResponsePage2.json"); - when(apiResponseService.fetchApiResponse(uriCoursePage1)).thenReturn(courseResponsePage1); - when(apiResponseService.fetchApiResponse(uriCoursePage2)).thenReturn(courseResponsePage2); - } - - @Test - @DisplayName("두루누비 테마 크롤링 테스트") - void testCrawlTheme() throws URISyntaxException, IOException { - // given - makeCrawlThemeMock(); - - // when - List themes = crawlDuruService.crawlTheme(); - - // then - assertFalse(themes.isEmpty()); - assertEquals(3, themes.size()); - } - - private void makeCrawlThemeMock() throws URISyntaxException, IOException { - URI uriThemePage1 = new URI("http://example.com/api/themes?page=1"); - URI uriThemePage2 = new URI("http://example.com/api/themes?page=2"); - - when(crawlApiBuilderHelper.buildUri(eq("routeList"), any(), eq(1), eq(100))).thenReturn(uriThemePage1); - when(crawlApiBuilderHelper.buildUri(eq("routeList"), any(), eq(2), eq(100))).thenReturn(uriThemePage2); - - String themeResponsePage1 = readJsonFile("mockedResponses/themeDuruResponsePage1.json"); - String themeResponsePage2 = readJsonFile("mockedResponses/themeDuruResponsePage2.json"); - when(apiResponseService.fetchApiResponse(uriThemePage1)).thenReturn(themeResponsePage1); - when(apiResponseService.fetchApiResponse(uriThemePage2)).thenReturn(themeResponsePage2); - } -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java deleted file mode 100644 index eb28a2e1..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.hubo.gillajabi.crawl.infraStructure.util.helper; - -import com.hubo.gillajabi.crawl.infrastructure.config.ApiProperties; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; -import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.net.URI; -import java.net.URISyntaxException; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class CrawlApiBuilderHelperTest { - - private CrawlApiBuilderHelper crawlApiBuilderHelper; - - private ApiProperties apiProperties; - - @Mock - private ValidatableResponse response; - - private static final String ENDPOINT_PATH = "testEndpoint"; - private static final String SITE_URL = "http://example.com/api/{}?serviceKey={serviceKey}&numOfRows={numOfRows}&pageNo={pageNo}"; - private static final String SERVICE_KEY = "testServiceKey"; - private static final int PAGE_NO = 1; - private static final int NUM_OF_ROWS = 10; - - @BeforeEach - public void setUp() { - crawlApiBuilderHelper = new CrawlApiBuilderHelper(); - - apiProperties = new ApiProperties(); - apiProperties.setSiteUrl(SITE_URL); - apiProperties.setEncoding(SERVICE_KEY); - } - - @Test - @DisplayName("buildUri 메서드 호출 시, 올바르게 URI 반환") - public void 유효한_입력일시_올바른_URI_반환() throws URISyntaxException { - // given 유효한 입력 값 - URI expectedUri = new URI("http://example.com/api/testEndpoint?serviceKey=testServiceKey&numOfRows=10&pageNo=1"); - - // when - URI resultUri = crawlApiBuilderHelper.buildUri(ENDPOINT_PATH, apiProperties, PAGE_NO, NUM_OF_ROWS); - - // then: 결과 URI가 예상 URI와 일치하는지 확인 - assertEquals(expectedUri, resultUri); - } - - @Test - @DisplayName("잘못된 변수로 buildUri 메서드 호출 시, URI 생성 실패") - public void 유효하지_않은_입력일시_URI생성실패() { - // given: 잘못된 siteUrl - String invalidSiteUrl = "http://[invalid-url]/api/{}?serviceKey={serviceKey}&numOfRows={numOfRows}&pageNo={pageNo}"; - apiProperties.setSiteUrl(invalidSiteUrl); - - // when - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - crawlApiBuilderHelper.buildUri(ENDPOINT_PATH, apiProperties, PAGE_NO, NUM_OF_ROWS); - }); - - //then - String expectedMessage = "URI 생성 실패"; - assertTrue(exception.getMessage().contains(expectedMessage)); - } - - @Test - @DisplayName("validateResponse 메서드 호출 시, response.validate() 메서드 호출") - public void validateResponse() { - // given - doNothing().when(response).validate(); - - // when - crawlApiBuilderHelper.validateResponse(response); - - // then - verify(response, times(1)).validate(); - } -} diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlResponseParserHelperTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlResponseParserHelperTest.java deleted file mode 100644 index fda1ee8f..00000000 --- a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlResponseParserHelperTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.hubo.gillajabi.crawl.infraStructure.util.helper; - -import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlResponseParserHelper; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -public class CrawlResponseParserHelperTest { - - @Test - @DisplayName("경남 김해시 -> 김해시로 파싱") - public void 경남_김해시를_김해시로_파싱_성공() { - // Given - String input = "경남 김해시"; - String expected = "김해시"; - - // When - String result = CrawlResponseParserHelper.parseDuruResponseByCity(input); - - // Then - assertEquals(expected, result); - } - - @Test - @DisplayName("경남김해시 공백이 없을경우 -> IllegalArgumentException 에러 발생") - public void 공백이_없는_지역명일때_파싱_실패() { - // Given - String input = "경남김해시"; // 공백이 없음 - - // When - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - CrawlResponseParserHelper.parseDuruResponseByCity(input); - }); - - // Then - String expectedMessage = "잘못된 포맷 형식 : " + input; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } - - @Test - @DisplayName("경남 김해시 -> 경남으로 파싱") - public void 경남_김해시_에서_김해시_파싱_성공() { - // Given - String input = "경남 김해시"; - String expected = "경남"; - - // When - String result = CrawlResponseParserHelper.parseDuruResponseByProvince(input); - - // Then - assertEquals(expected, result); - } -} diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java new file mode 100644 index 00000000..ecf07737 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java @@ -0,0 +1,104 @@ +package com.hubo.gillajabi.road.application.service; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +import com.hubo.gillajabi.crawl.application.service.*; +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; +import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.navercorp.fixturemonkey.FixtureMonkey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +public class RoadCrawlFacadeServiceTest { + + @Mock + private RoadDuruCourseHandler roadDuruCourseHandler; + + @Mock + private RoadCrawlBusanCourseHandler roadCrawlBusanCourseHandler; + + @Mock + private RoadDuruThemeHandler roadDuruThemeHandler; + + @Mock + private RoadBusanThemeHandler roadBusanThemeHandler; + + @InjectMocks + private RoadCrawlFacadeService roadCrawlFacadeService; + + private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); + + @Test + @DisplayName("두루 코스를 제대로 호출") + public void testGetDuruCourse() { + // given + RoadCrawlResponse.CourseResult duruCourseResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.CourseResult.class) + .sample(); + + when(roadDuruCourseHandler.handle()).thenReturn(duruCourseResult); + + // when + assertEquals(duruCourseResult, roadCrawlFacadeService.getCourse(CityName.DURU)); + + // then + verify(roadDuruCourseHandler).handle(); + verifyNoMoreInteractions(roadDuruThemeHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); + } + + @Test + @DisplayName("부산 코스를 제대로 호출") + public void testGetBusanCourse() { + // given + RoadCrawlResponse.CourseResult busanCourseResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.CourseResult.class) + .sample(); + + when(roadCrawlBusanCourseHandler.handle()).thenReturn(busanCourseResult); + + // when + assertEquals(busanCourseResult, roadCrawlFacadeService.getCourse(CityName.BUSAN)); + + // then + verify(roadCrawlBusanCourseHandler).handle(); + verifyNoMoreInteractions(roadDuruCourseHandler, roadDuruThemeHandler, roadBusanThemeHandler); + } + + @Test + @DisplayName("두루 테마를 제대로 호출") + public void testGetDuruTheme() { + // given + RoadCrawlResponse.ThemeResult duruThemeResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.ThemeResult.class) + .sample(); + + when(roadDuruThemeHandler.handle()).thenReturn(duruThemeResult); + + // when + assertEquals(duruThemeResult, roadCrawlFacadeService.getTheme(CityName.DURU)); + + // then + verify(roadDuruThemeHandler).handle(); + verifyNoMoreInteractions(roadDuruCourseHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); + } + + @Test + @DisplayName("부산 테마를 제대로 호출") + public void testGetBusanTheme() { + // given + RoadCrawlResponse.ThemeResult busanThemeResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.ThemeResult.class) + .sample(); + + when(roadBusanThemeHandler.handle()).thenReturn(busanThemeResult); + + // when + assertEquals(busanThemeResult, roadCrawlFacadeService.getTheme(CityName.BUSAN)); + + // then + verify(roadBusanThemeHandler).handle(); + verifyNoMoreInteractions(roadDuruCourseHandler, roadDuruThemeHandler, roadCrawlBusanCourseHandler); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandlerTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java similarity index 68% rename from src/test/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandlerTest.java rename to src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java index 54d7f510..955ee3fc 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/application/service/DuruCourseHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java @@ -1,15 +1,18 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.road.application.service; -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; +import com.hubo.gillajabi.crawl.application.service.RoadDuruCourseHandler; +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.*; import com.hubo.gillajabi.crawl.domain.service.duru.*; +import com.hubo.gillajabi.road.domain.entity.*; +import com.hubo.gillajabi.road.domain.service.road.duru.*; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,30 +28,30 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class DuruCourseHandlerTest { +class RoadDuruCourseHandlerTest { @Mock - private CrawlDuruServiceImpl duruCrawlService; + private RoadCrawlDuruServiceImpl duruCrawlService; @Mock - private CityDuruService cityService; + private RoadCityDuruService cityService; @Mock - private CourseDuruService courseDuruService; + private RoadCourseDuruService roadCourseDuruService; @Mock - private CourseDetailDuruService courseDetailDuruService; + private RoadCourseDetailDuruService roadCourseDetailDuruService; @Mock - private GpxInfoDuruService gpxInfoDuruService; + private RoadGpxInfoDuruService roadGpxInfoDuruService; @InjectMocks - private DuruCourseHandler duruCourseHandler; + private RoadDuruCourseHandler roadDuruCourseHandler; private static final FixtureMonkey fixtureMonkey = FixtureMonkey.builder().build(); - public DuruCourseResponse.Course createDuruCourseResponse(){ - DuruCourseResponse.Course response = fixtureMonkey.giveMeBuilder(DuruCourseResponse.Course.class).sample(); + public ApiCourseResponse.Course createDuruCourseResponse(){ + ApiCourseResponse.Course response = fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class).sample(); response.setCrsKorNm("남해랑길 1코스"); response.setCrsLevel("1"); response.setGpxpath("http://example.com"); @@ -63,7 +66,7 @@ private static CourseDetail createCourseDetail() { return CourseDetail.createCourseDetail(courseDetailRequestDTO); } - private static Course createCourse(DuruCourseResponse.Course mockCourseDuruResponse, City mockCity, CourseTheme mockCourseTheme) { + private static Course createCourse(ApiCourseResponse.Course mockCourseDuruResponse, City mockCity, CourseTheme mockCourseTheme) { CourseRequestDTO courseRequestDTO = CourseRequestDTO.of(mockCourseDuruResponse, mockCity, mockCourseTheme); courseRequestDTO.setCity(mockCity); courseRequestDTO.setLevel(CourseLevel.fromValue(mockCourseDuruResponse.getCrsLevel())); @@ -76,13 +79,13 @@ private static CourseTheme createCourseTheme() { return CourseTheme.createCourseTheme(courseThemeRequestDTO); } - private static City createCity(DuruCourseResponse.Course mockCourseDuruResponse) { + private static City createCity(ApiCourseResponse.Course mockCourseDuruResponse) { CityRequestDTO cityRequestDTO = CityRequestDTO.of(mockCourseDuruResponse.getCrsKorNm(), Province.GYEONGGI, "짧은소개글"); return City.createCity(cityRequestDTO); } private void mockDuruHandle() { - DuruCourseResponse.Course mockCourseDuruResponse = createDuruCourseResponse(); + ApiCourseResponse.Course mockCourseDuruResponse = createDuruCourseResponse(); City mockCity = createCity(mockCourseDuruResponse); CourseTheme mockCourseTheme = createCourseTheme(); Course mockCourse = createCourse(mockCourseDuruResponse, mockCity, mockCourseTheme); @@ -91,9 +94,9 @@ private void mockDuruHandle() { when(duruCrawlService.crawlCourse()).thenReturn(List.of(mockCourseDuruResponse)); when(cityService.saveCity(anyList())).thenReturn(List.of(mockCity)); - when(courseDuruService.saveDuruCourse(anyList(), anyList())).thenReturn(List.of(mockCourse)); - when(courseDetailDuruService.saveDuruCourseDetail(anyList(), anyList())).thenReturn(List.of(mockCourseDetail)); - when(gpxInfoDuruService.saveGpxInfo(anyList())).thenReturn(List.of(mockGpxInfo)); + when(roadCourseDuruService.saveDuruCourse(anyList(), anyList())).thenReturn(List.of(mockCourse)); + when(roadCourseDetailDuruService.saveDuruCourseDetail(anyList(), anyList())).thenReturn(List.of(mockCourseDetail)); + when(roadGpxInfoDuruService.saveGpxInfo(anyList())).thenReturn(List.of(mockGpxInfo)); } @@ -104,7 +107,7 @@ void testHandle() { mockDuruHandle(); // when - CrawlResponse.CourseResult result = duruCourseHandler.handle(); + RoadCrawlResponse.CourseResult result = roadDuruCourseHandler.handle(); // then assertEquals(1, result.getCityCount()); diff --git a/src/test/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandlerTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java similarity index 58% rename from src/test/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandlerTest.java rename to src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java index ec33b1dc..dc4c8da6 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/application/service/DuruThemeHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java @@ -1,11 +1,12 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.road.application.service; -import com.hubo.gillajabi.crawl.application.dto.response.CrawlResponse; +import com.hubo.gillajabi.crawl.application.service.RoadDuruThemeHandler; +import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.CourseDuruThemeService; -import com.hubo.gillajabi.crawl.domain.service.duru.CrawlDuruServiceImpl; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruThemeService; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCrawlDuruServiceImpl; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,16 +22,16 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class DuruThemeHandlerTest { +class RoadDuruThemeHandlerTest { @Mock - private CrawlDuruServiceImpl duruCrawlService; + private RoadCrawlDuruServiceImpl duruCrawlService; @Mock - private CourseDuruThemeService courseDuruThemeService; + private RoadCourseDuruThemeService roadCourseDuruThemeService; @InjectMocks - private DuruThemeHandler duruThemeHandler; + private RoadDuruThemeHandler roadDuruThemeHandler; @Test @DisplayName("두루누비 테마를 제대로 호출") @@ -39,7 +40,7 @@ void testHandle() { FixtureMonkey fixtureMonkey = FixtureMonkey.create(); // Mock 생성 - List mockResponseItems = fixtureMonkey.giveMe(DuruThemeResponse.Theme.class, 5); + List mockResponseItems = fixtureMonkey.giveMe(ApiThemeResponse.Theme.class, 5); // CourseTheme 생성 List mockThemes = mockResponseItems.stream() @@ -48,14 +49,14 @@ void testHandle() { .collect(Collectors.toList()); when(duruCrawlService.crawlTheme()).thenReturn(mockResponseItems); - when(courseDuruThemeService.saveDuruTheme(anyList())).thenReturn(mockThemes); + when(roadCourseDuruThemeService.saveDuruTheme(anyList())).thenReturn(mockThemes); // when - CrawlResponse.ThemeResult result = duruThemeHandler.handle(); + RoadCrawlResponse.ThemeResult result = roadDuruThemeHandler.handle(); // then assertEquals(mockThemes.size(), result.getThemeCount()); verify(duruCrawlService).crawlTheme(); - verify(courseDuruThemeService).saveDuruTheme(mockResponseItems); + verify(roadCourseDuruThemeService).saveDuruTheme(mockResponseItems); } } diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java b/src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java similarity index 72% rename from src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java index 1dfdc7e3..d9a6e795 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java @@ -1,6 +1,7 @@ -package com.hubo.gillajabi.crawl.domain.constant; +package com.hubo.gillajabi.road.domain.constant; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.domain.constant.CycleType; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -12,7 +13,7 @@ class CycleTypeTest { @Test @DisplayName("순환형은 CYCLE 반환") void 두루누비_순환형일경우_CYCLE반환(){ - DuruCourseResponse.Course course = new DuruCourseResponse.Course(); + ApiCourseResponse.Course course = new ApiCourseResponse.Course(); course.setCrsCycle("순환형"); assertEquals(CycleType.CYCLE, CycleType.fromValue(course)); @@ -21,7 +22,7 @@ class CycleTypeTest { @Test @DisplayName("비순환형이면 SINGLE 반환") void 두루누비_비순환형일경우_SINGLE반환(){ - DuruCourseResponse.Course course = new DuruCourseResponse.Course(); + ApiCourseResponse.Course course = new ApiCourseResponse.Course(); course.setCrsCycle("비순환형"); assertEquals(CycleType.SINGLE, CycleType.fromValue(course)); @@ -30,7 +31,7 @@ class CycleTypeTest { @Test @DisplayName("잘못된 순환형 값 예외 발생") void 두루누비_순환형이_잘못된_값일_경우(){ - DuruCourseResponse.Course course = new DuruCourseResponse.Course(); + ApiCourseResponse.Course course = new ApiCourseResponse.Course(); course.setCrsCycle("잘못된 값"); Exception exception = assertThrows(IllegalArgumentException.class, () -> CycleType.fromValue(course)); diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java similarity index 96% rename from src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java index 0057186f..1a831f0a 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java @@ -1,5 +1,6 @@ -package com.hubo.gillajabi.crawl.domain.constant; +package com.hubo.gillajabi.road.domain.constant; +import com.hubo.gillajabi.crawl.domain.constant.Province; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java similarity index 74% rename from src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java index eebfa373..ff786a3e 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CityDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java @@ -1,17 +1,16 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; +package com.hubo.gillajabi.road.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.City; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCityDuruService; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; -import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlResponseParserHelper; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; @@ -23,13 +22,13 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class CityDuruServiceTest { +class RoadCityDuruServiceTest { @Mock private CityRepository cityRepository; @InjectMocks - private CityDuruService cityDuruService; + private RoadCityDuruService roadCityDuruService; private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); @@ -42,14 +41,14 @@ public void findByNameAndProvince() { @Test void DuruCourseResponse_Course를_받아서_새로운_city객체를_생성하고_저장() { // given - List responseItems = fixtureMonkey.giveMeBuilder(DuruCourseResponse.Course.class) + List responseItems = fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class) .set("sigun", "경남 김해시") .sampleList(1); findByNameAndProvince(); // when - List savedCities = cityDuruService.saveCity(responseItems); + List savedCities = roadCityDuruService.saveCity(responseItems); // then assertEquals(1, savedCities.size()); diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java similarity index 82% rename from src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java index 159c9d7d..be893b65 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDetailDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; +package com.hubo.gillajabi.road.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; @@ -6,10 +6,11 @@ import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDetailDuruService; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseDetailRepository; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; import com.navercorp.fixturemonkey.FixtureMonkey; @@ -28,7 +29,7 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class CourseDetailDuruServiceTest { +class RoadCourseDetailDuruServiceTest { @Mock private CourseDetailRepository courseDetailRepository; @@ -37,12 +38,12 @@ class CourseDetailDuruServiceTest { private CourseRepository courseRepository; @InjectMocks - private CourseDetailDuruService courseDetailDuruService; + private RoadCourseDetailDuruService roadCourseDetailDuruService; private static final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); - public DuruCourseResponse.Course giveMeDuruCourseResponse(){ - DuruCourseResponse.Course response = fixtureMonkey.giveMeBuilder(DuruCourseResponse.Course.class).sample(); + public ApiCourseResponse.Course giveMeDuruCourseResponse(){ + ApiCourseResponse.Course response = fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class).sample(); response.setCrsKorNm("남해랑길 1코스"); response.setCrsLevel("1"); response.setGpxpath("http://example.com"); @@ -68,7 +69,7 @@ public CourseThemeRequestDTO giveMeCourseThemeRequestDTO(){ } public CourseRequestDTO giveMeCourseRequestDTO() { - DuruCourseResponse.Course response = giveMeDuruCourseResponse(); + ApiCourseResponse.Course response = giveMeDuruCourseResponse(); City city = City.createCity(giveMeCityRequestDTO()); CourseTheme courseTheme = CourseTheme.createCourseTheme(giveMeCourseThemeRequestDTO()); @@ -82,14 +83,14 @@ public CourseRequestDTO giveMeCourseRequestDTO() { List courses = new ArrayList<>(); courses.add(Course.createCourse(giveMeCourseRequestDTO())); - List responseItems = new ArrayList<>(); + List responseItems = new ArrayList<>(); responseItems.add(giveMeDuruCourseResponse()); when(courseRepository.save(any(Course.class))).thenAnswer(invocation -> invocation.getArgument(0)); when(courseDetailRepository.save(any(CourseDetail.class))).thenAnswer(invocation -> invocation.getArgument(0)); // when - List savedCourseDetails = courseDetailDuruService.saveDuruCourseDetail(responseItems, courses); + List savedCourseDetails = roadCourseDetailDuruService.saveDuruCourseDetail(responseItems, courses); // then assertEquals(1, savedCourseDetails.size()); diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java similarity index 81% rename from src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java index 787febcb..7254337d 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/CourseDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java @@ -1,13 +1,14 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; +package com.hubo.gillajabi.road.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruService; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; import com.navercorp.fixturemonkey.FixtureMonkey; @@ -27,7 +28,7 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class CourseDuruServiceTest { +class RoadCourseDuruServiceTest { @Mock private CourseRepository courseRepository; @@ -36,7 +37,7 @@ class CourseDuruServiceTest { private CourseThemeRepository courseThemeRepository; @InjectMocks - private CourseDuruService courseDuruService; + private RoadCourseDuruService roadCourseDuruService; private final static FixtureMonkey fixtureMonkey = FixtureMonkey.create(); @@ -49,8 +50,8 @@ public City createCity() { return City.createCity(cityRequestDTO); } - public DuruCourseResponse.Course createDuruCourseResponseCourse() { - DuruCourseResponse.Course response = fixtureMonkey.giveMeBuilder(DuruCourseResponse.Course.class).sample(); + public ApiCourseResponse.Course createDuruCourseResponseCourse() { + ApiCourseResponse.Course response = fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class).sample(); response.setCrsKorNm("남해랑길 1코스"); response.setCrsLevel("1"); response.setGpxpath("http://example.com"); @@ -72,8 +73,8 @@ public void saveDuruCourse() { City city = createCity(); cities.add(city); - List responseItems = new ArrayList<>(); - DuruCourseResponse.Course response = createDuruCourseResponseCourse(); + List responseItems = new ArrayList<>(); + ApiCourseResponse.Course response = createDuruCourseResponseCourse(); responseItems.add(response); CourseThemeRequestDTO courseThemeRequestDTO = fixtureMonkey.giveMeBuilder(CourseThemeRequestDTO.class).sample(); @@ -84,7 +85,7 @@ public void saveDuruCourse() { when(courseRepository.save(any())).thenReturn(Course.createCourse(CourseRequestDTO.of(response, city, courseTheme))); // when - List courses = courseDuruService.saveDuruCourse(responseItems, cities); + List courses = roadCourseDuruService.saveDuruCourse(responseItems, cities); // then assertEquals(1, courses.size()); diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java similarity index 81% rename from src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java index 3b382b4f..544030bd 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/GpxInfoDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java @@ -1,11 +1,14 @@ -package com.hubo.gillajabi.crawl.domain.service.duru; +package com.hubo.gillajabi.road.domain.service.duru; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import com.hubo.gillajabi.crawl.domain.entity.*; -import com.hubo.gillajabi.crawl.domain.service.ApiResponseService; +import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; +import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadGpxInfoDuruService; +import com.hubo.gillajabi.road.domain.entity.*; +import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; @@ -28,16 +31,16 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class GpxInfoDuruServiceTest { +class RoadGpxInfoDuruServiceTest { @Mock private GpxInfoRepository gpxInfoRepository; @Mock - private ApiResponseService apiResponseService; + private ResponseCrawlService responseCrawlService; @InjectMocks - private GpxInfoDuruService gpxInfoDuruService; + private RoadGpxInfoDuruService roadGpxInfoDuruService; private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); @@ -56,7 +59,7 @@ public void mockApiResponseService() throws JsonProcessingException { String xmlResponse = xmlMapper.writeValueAsString(duruGpxResponse); // API 응답을 모킹 - when(apiResponseService.fetchApiResponse(any(URI.class))) + when(responseCrawlService.fetchApiResponse(any(URI.class))) .thenReturn(xmlResponse); } @@ -79,7 +82,7 @@ public void testSaveGpxInfoWithValidCourseDetails() throws JsonProcessingExcepti mockApiResponseService(); // when - List savedGpxInfos = gpxInfoDuruService.saveGpxInfo(mockCourseDetails); + List savedGpxInfos = roadGpxInfoDuruService.saveGpxInfo(mockCourseDetails); // then assertEquals(mockCourseDetails.size(), savedGpxInfos.size()); @@ -101,7 +104,7 @@ public void testSaveGpxInfoWithValidCourseDetails() throws JsonProcessingExcepti .toList(); //when - List savedGpxInfos = gpxInfoDuruService.saveGpxInfo(mockCourseDetails); + List savedGpxInfos = roadGpxInfoDuruService.saveGpxInfo(mockCourseDetails); //then assertEquals(0, savedGpxInfos.size()); diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadPropertiesTest.java b/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java similarity index 74% rename from src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadPropertiesTest.java rename to src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java index 6e6e23c3..0c71b28f 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadPropertiesTest.java +++ b/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java @@ -1,8 +1,8 @@ -package com.hubo.gillajabi.crawl.infraStructure.config; +package com.hubo.gillajabi.road.infraStructure.config; import com.hubo.gillajabi.crawl.domain.constant.CityName; -import com.hubo.gillajabi.crawl.infrastructure.config.ApiProperties; -import com.hubo.gillajabi.crawl.infrastructure.config.RoadProperties; +import com.hubo.gillajabi.global.common.dto.ApiProperties; +import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,22 +13,22 @@ @SpringBootTest @ActiveProfiles("test") -class RoadPropertiesTest { +class RoadEndpointConfigTest { @Autowired - private RoadProperties roadProperties; + private RoadEndpointConfig roadEndpointConfig; @Test @DisplayName("road-yml에 정의된 road를 올바르게 읽어온다.") void testRoadProperties() { - ApiProperties duruProperties = roadProperties.getEndpoint(CityName.DURU); + ApiProperties duruProperties = roadEndpointConfig.getEndpoint(CityName.DURU); assertThat(duruProperties).isNotNull(); assertThat(duruProperties.getEndpoint()).isEqualTo("http://example.com"); assertThat(duruProperties.getEncoding()).isEqualTo("serviceKey"); assertThat(duruProperties.getDecoding()).isEqualTo("serviceKey"); assertThat(duruProperties.getSiteUrl()).isEqualTo("http://example.com"); - ApiProperties busanProperties = roadProperties.getEndpoint(CityName.BUSAN); + ApiProperties busanProperties = roadEndpointConfig.getEndpoint(CityName.BUSAN); assertThat(busanProperties).isNotNull(); assertThat(busanProperties.getEndpoint()).isEqualTo("http://example.com"); assertThat(busanProperties.getEncoding()).isEqualTo("serviceKey"); From 860977763423671cafd145b3daf5ae1fca961e1a Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Tue, 25 Jun 2024 22:16:38 +0900 Subject: [PATCH 02/31] =?UTF-8?q?feat:=20WeatherEndpointConfig=20key=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/WeatherEndpointConfig.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/WeatherEndpointConfig.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/WeatherEndpointConfig.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/WeatherEndpointConfig.java new file mode 100644 index 00000000..44040ff7 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/WeatherEndpointConfig.java @@ -0,0 +1,22 @@ +package com.hubo.gillajabi.crawl.infrastructure.config; + +import com.hubo.gillajabi.global.common.dto.ApiProperties; +import com.hubo.gillajabi.crawl.domain.constant.ForecastType; +import lombok.Getter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.EnumMap; +import java.util.Map; + +@Configuration +@ConfigurationProperties(prefix = "weather") +@Getter +public class WeatherEndpointConfig { + + private final Map weatherEndpoints = new EnumMap<>(ForecastType.class); + + public Map getEndPoint() { + return weatherEndpoints; + } +} From 445116b063117c563e9187b639d11cd628da7475 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Tue, 25 Jun 2024 22:17:43 +0900 Subject: [PATCH 03/31] =?UTF-8?q?feat:=20weather=20=EA=B4=80=EB=A0=A8=20en?= =?UTF-8?q?um=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawl/domain/constant/ForecastType.java | 7 ++++ .../domain/constant/PrecipitationForm.java | 36 +++++++++++++++++++ .../crawl/domain/constant/SkyCondition.java | 29 +++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/ForecastType.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationForm.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/SkyCondition.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/ForecastType.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/ForecastType.java new file mode 100644 index 00000000..78b76f8e --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/ForecastType.java @@ -0,0 +1,7 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +public enum ForecastType { + CURRENT, // 당일 예보 + MEDIUM_TERM, // 중기 예보 + WEATHER_ALERT // 기상 특보 +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationForm.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationForm.java new file mode 100644 index 00000000..53012263 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationForm.java @@ -0,0 +1,36 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +public enum PrecipitationForm { + NONE(0, "없음"), + RAIN(1, "비"), + RAIN_AND_SNOW(2, "비/눈"), + SNOW(3, "눈"), + SHOWER(4, "소나기"); + + private final int code; + private final String description; + + PrecipitationForm(int code, String description) { + this.code = code; + this.description = description; + } + + public int getCode() { + return code; + } + + public String getDescription() { + return description; + } + + public static PrecipitationForm fromCode(int code) { + return switch (code) { + case 0 -> NONE; + case 1 -> RAIN; + case 2 -> RAIN_AND_SNOW; + case 3 -> SNOW; + case 4 -> SHOWER; + default -> throw new IllegalArgumentException("잘못된 강수형태 " + code); + }; + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/SkyCondition.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/SkyCondition.java new file mode 100644 index 00000000..5ffb5b26 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/SkyCondition.java @@ -0,0 +1,29 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import lombok.Getter; + +@Getter +public enum SkyCondition { + CLEAR(1, "맑음"), + PARTLY_CLOUDY(2, "구름조금"), + MOSTLY_CLOUDY(3, "구름많음"), + CLOUDY(4, "흐림"); + + private final int code; + private final String description; + + SkyCondition(int code, String description) { + this.code = code; + this.description = description; + } + + public static SkyCondition fromCode(int code) { + return switch (code) { + case 1 -> CLEAR; + case 2 -> PARTLY_CLOUDY; + case 3 -> MOSTLY_CLOUDY; + case 4 -> CLOUDY; + default -> throw new IllegalArgumentException("잘못된 하늘 상태 코드 : " + code); + }; + } +} From ec85964c8ba627d2b6a64ea16cf5c2a3d4cdd568 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Tue, 25 Jun 2024 22:18:07 +0900 Subject: [PATCH 04/31] =?UTF-8?q?chore:=20=EC=95=88=20=EC=93=B0=EB=8A=94?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hubo/gillajabi/crawl/domain/constant/CrawlType.java | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/CrawlType.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CrawlType.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CrawlType.java deleted file mode 100644 index 7f33b296..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CrawlType.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.hubo.gillajabi.crawl.domain.constant; - -public enum CrawlType { - COURSE, - THEME, -} From 62309e02f1c2e873f559162f18a617767597ed60 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:40:01 +0900 Subject: [PATCH 05/31] =?UTF-8?q?feat:=20ApiResponse=20dto=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...xResponse.java => ApiDuruGpxResponse.java} | 2 +- .../response/ApiWeatherCurrentResponse.java | 24 ++++++++++ .../ApiWeatherMediumTermResponse.java | 46 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/{DuruGpxResponse.java => ApiDuruGpxResponse.java} (98%) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherCurrentResponse.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruGpxResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiDuruGpxResponse.java similarity index 98% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruGpxResponse.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiDuruGpxResponse.java index 5ebd9796..268677cc 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/DuruGpxResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiDuruGpxResponse.java @@ -14,7 +14,7 @@ @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) // 알려지지 않은 속성 무시 -public class DuruGpxResponse { +public class ApiDuruGpxResponse { @JacksonXmlProperty(localName = "metadata") private Metadata metadata; diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherCurrentResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherCurrentResponse.java new file mode 100644 index 00000000..38b676cd --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherCurrentResponse.java @@ -0,0 +1,24 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.response; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Getter; +import lombok.Setter; + + +public class ApiWeatherCurrentResponse extends AbstractApiResponse { + + @Getter + @Setter + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Current { + private String baseDate; + private String baseTime; + private String category; + private String fcstDate; + private String fcstTime; + private String fcstValue; + private int nx; + private int ny; + } +} + diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java new file mode 100644 index 00000000..8cab2067 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java @@ -0,0 +1,46 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.response; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Getter; +import lombok.Setter; + +public class ApiWeatherMediumTermResponse { + + @Getter + @Setter + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MediumTerm { + private String regId; + private int taMin3; + private int taMin3Low; + private int taMin3High; + private int taMax3; + private int taMax3Low; + private int taMax3High; + private int taMin4; + private int taMin4Low; + private int taMin4High; + private int taMax4; + private int taMax4Low; + private int taMax4High; + private int taMin5; + private int taMin5Low; + private int taMin5High; + private int taMax5; + private int taMax5Low; + private int taMax5High; + private int taMin6; + private int taMin6Low; + private int taMin6High; + private int taMax6; + private int taMax6Low; + private int taMax6High; + private int taMin7; + private int taMin7Low; + private int taMin7High; + private int taMax7; + private int taMax7Low; + private int taMax7High; + } + +} From caf4a87db11d30fb544fd45dcc81f0b23224fce3 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:40:25 +0900 Subject: [PATCH 06/31] =?UTF-8?q?feat:=20City=20Entity=20=EC=97=90=20?= =?UTF-8?q?=EB=82=A0=EC=94=A8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hubo/gillajabi/crawl/domain/entity/City.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/City.java b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/City.java index 432d17c9..ae2a9c29 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/City.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/City.java @@ -1,7 +1,7 @@ package com.hubo.gillajabi.crawl.domain.entity; import com.hubo.gillajabi.crawl.domain.constant.Province; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; import jakarta.persistence.*; import lombok.*; @@ -26,7 +26,17 @@ public class City { @Column private String description; - public static City createCity(final CityRequestDTO cityRequestDTO) { - return new City(null, cityRequestDTO.getName(), cityRequestDTO.getProvince(), cityRequestDTO.getDescription()); + @Column + private Integer nx; + + @Column + private Integer ny; + + @Column(length = 8) + private String cityCode; + + public static City createCity(final CityRequest cityRequest) { + return new City(null, cityRequest.getName(), cityRequest.getProvince(), cityRequest.getDescription(),null + ,null,null); } } From e520e079d93cf5624f6a3891e3b60090b356cd5c Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:40:57 +0900 Subject: [PATCH 07/31] =?UTF-8?q?refactor:=20CityCrawl=20=EB=A5=BC=20CityC?= =?UTF-8?q?rawlName=20=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/constant/{CityName.java => CityCrawlName.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/domain/constant/{CityName.java => CityCrawlName.java} (78%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityName.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityCrawlName.java similarity index 78% rename from src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityName.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityCrawlName.java index 64f42955..b7c1a01d 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityName.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/CityCrawlName.java @@ -1,12 +1,12 @@ package com.hubo.gillajabi.crawl.domain.constant; -public enum CityName { +public enum CityCrawlName { DURU("두루누비"), BUSAN("부산"); private final String name; - CityName(String name) { + CityCrawlName(String name) { this.name = name; } From 3e7b2598ce82201cc3736ff6748cfef67b226bf0 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:41:39 +0900 Subject: [PATCH 08/31] =?UTF-8?q?refactor:=20dto=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=93=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?-=20request=EB=81=9D=EC=97=90=20dto=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/CityRequest.java | 26 +++++++++++++++++++ .../dto/request/CityRequestDTO.java | 26 ------------------- .../dto/request/CourseThemeRequest.java | 24 +++++++++++++++++ .../dto/request/CourseThemeRequestDTO.java | 20 -------------- 4 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequest.java delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequestDTO.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequest.java delete mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequestDTO.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequest.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequest.java new file mode 100644 index 00000000..7a401377 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequest.java @@ -0,0 +1,26 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.request; + +import com.hubo.gillajabi.crawl.domain.constant.Province; +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class CityRequest { + + private String name; + + private Province province; + + private String description; + + public static CityRequest of(final String name, final Province province, final String description) { + return new CityRequest(name, province, description); + } + + public static CityRequest of(final String name, final Province province) { + return new CityRequest(name, province, null); + } +} + diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequestDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequestDTO.java deleted file mode 100644 index 06bde805..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CityRequestDTO.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.hubo.gillajabi.crawl.infrastructure.dto.request; - -import com.hubo.gillajabi.crawl.domain.constant.Province; -import lombok.*; - -@Getter -@Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class CityRequestDTO { - - private String name; - - private Province province; - - private String description; - - public static CityRequestDTO of(final String name, final Province province, final String description) { - return new CityRequestDTO(name, province, description); - } - - public static CityRequestDTO of(final String name, final Province province) { - return new CityRequestDTO(name, province, null); - } -} - diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequest.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequest.java new file mode 100644 index 00000000..95ede7bd --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequest.java @@ -0,0 +1,24 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.request; + +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; +import lombok.*; +import org.jsoup.Jsoup; + +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class CourseThemeRequest { + + private String name; + private String shortDescription; + private String description; + + public static CourseThemeRequest from(ApiThemeResponse.Theme item) { + return new CourseThemeRequest(item.getThemeNm(), item.getLinemsg(), extractText(item.getThemedescs())); + } + + private static String extractText(String htmlContent) { + return Jsoup.parse(htmlContent).text(); + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequestDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequestDTO.java deleted file mode 100644 index c973c0ab..00000000 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseThemeRequestDTO.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hubo.gillajabi.crawl.infrastructure.dto.request; - -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruThemeResponse; -import lombok.*; - -@Getter -@Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class CourseThemeRequestDTO { - - private String name; - private String shortDescription; - private String description; - - public static CourseThemeRequestDTO from(DuruThemeResponse.Theme item) { - return new CourseThemeRequestDTO(item.getThemeNm(), item.getLinemsg(), item.getThemedescs()); - } - -} From 92ae153ea634763f491ad22147c2700f15d963fe Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:42:02 +0900 Subject: [PATCH 09/31] =?UTF-8?q?feat:=20redis=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 84881977..14dbd5ff 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' testImplementation 'org.springframework.boot:spring-boot-starter-test' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis + implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.2.5' + + // https://mvnrepository.com/artifact/junit/junit testImplementation 'junit:junit:4.13.1' From 4066fcb730c75c38191b5e30ef639d96263a4088 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:43:00 +0900 Subject: [PATCH 10/31] =?UTF-8?q?refactor:=20dto=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=9D=B4=EB=A6=84=EC=9D=B4=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EB=90=A8=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hubo/gillajabi/crawl/domain/entity/Course.java | 8 ++++---- .../hubo/gillajabi/crawl/domain/entity/CourseDetail.java | 8 ++++---- ...urseDetailRequestDTO.java => CourseDetailRequest.java} | 8 ++++---- .../request/{CourseRequestDTO.java => CourseRequest.java} | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/{CourseDetailRequestDTO.java => CourseDetailRequest.java} (76%) rename src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/{CourseRequestDTO.java => CourseRequest.java} (83%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/Course.java b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/Course.java index 83fa17a7..21e02af0 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/Course.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/Course.java @@ -2,7 +2,7 @@ import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; import com.hubo.gillajabi.global.BaseEntity; import jakarta.persistence.*; import lombok.*; @@ -56,13 +56,13 @@ public class Course extends BaseEntity { private City city; - public static Course createCourse(final CourseRequestDTO request) { + public static Course createCourse(final CourseRequest request) { return new Course(null, request.getCourseName(), request.getDistance(), request.getTotalRequiredHours(), request.getLevel(), request.getShortDescription(), request.getCourseNumber(), null, null, null, request.getCourseTheme(), request.getCity()); } - public boolean checkUpdate(final CourseRequestDTO request) { + public boolean checkUpdate(final CourseRequest request) { boolean isUpdated = false; if (!this.originName.equals(request.getCourseName())) { @@ -100,7 +100,7 @@ public boolean checkUpdate(final CourseRequestDTO request) { return isUpdated; } - public void update(final CourseRequestDTO request) { + public void update(final CourseRequest request) { this.originName = request.getCourseName(); this.distance = request.getDistance(); this.totalTimeRequired = request.getTotalRequiredHours(); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseDetail.java b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseDetail.java index f2720983..8b309c58 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseDetail.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseDetail.java @@ -1,7 +1,7 @@ package com.hubo.gillajabi.crawl.domain.entity; import com.hubo.gillajabi.crawl.domain.constant.CycleType; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; import com.hubo.gillajabi.global.BaseEntity; import jakarta.persistence.*; import lombok.*; @@ -47,7 +47,7 @@ public class CourseDetail extends BaseEntity { @Enumerated(EnumType.STRING) private CycleType cycleType; // 순환 여부 - public static CourseDetail createCourseDetail(final CourseDetailRequestDTO request) { + public static CourseDetail createCourseDetail(final CourseDetailRequest request) { return new CourseDetail( null, request.getTourInfo(), @@ -62,7 +62,7 @@ public static CourseDetail createCourseDetail(final CourseDetailRequestDTO reque ); } - public void update(final CourseDetailRequestDTO request) { + public void update(final CourseDetailRequest request) { this.tourInfo = request.getTourInfo(); this.courseDescription = request.getCourseDescription(); this.startPoint = request.getStartPoint(); @@ -74,7 +74,7 @@ public void update(final CourseDetailRequestDTO request) { this.cycleType = request.getCycleType(); } - public boolean isCheckUpdate(final CourseDetailRequestDTO request) { + public boolean isCheckUpdate(final CourseDetailRequest request) { return !Objects.equals(this.tourInfo, request.getTourInfo()) || !Objects.equals(this.courseDescription, request.getCourseDescription()) || !Objects.equals(this.startPoint, request.getStartPoint()) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequest.java similarity index 76% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequest.java index f1b5b5c5..e4a424ee 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequestDTO.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseDetailRequest.java @@ -8,7 +8,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class CourseDetailRequestDTO { +public class CourseDetailRequest { private String courseName; private String tourInfo; private String courseDescription; @@ -22,9 +22,9 @@ public class CourseDetailRequestDTO { private CycleType cycleType; - public static CourseDetailRequestDTO of(final ApiCourseResponse.Course item, final String startPoint, final String endPoint, - final String startPointTransport, final String endPointTransport) { - return new CourseDetailRequestDTO( + public static CourseDetailRequest of(final ApiCourseResponse.Course item, final String startPoint, final String endPoint, + final String startPointTransport, final String endPointTransport) { + return new CourseDetailRequest( item.getCrsKorNm(), item.getCrsTourInfo(), item.getCrsContents(), diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequestDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java similarity index 83% rename from src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequestDTO.java rename to src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java index f9203f75..1681530a 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequestDTO.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java @@ -3,7 +3,7 @@ import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import lombok.*; import org.jsoup.Jsoup; @@ -11,7 +11,7 @@ @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor -public class CourseRequestDTO { +public class CourseRequest { private String courseName; private Integer distance; private Integer totalRequiredHours; @@ -21,11 +21,11 @@ public class CourseRequestDTO { private City city; private CourseTheme courseTheme; - public static CourseRequestDTO of(DuruCourseResponse.Course item, City city, CourseTheme courseTheme) { + public static CourseRequest of(ApiCourseResponse.Course item, City city, CourseTheme courseTheme) { CourseLevel level = CourseLevel.fromValue(item.getCrsLevel()); String shortDescription = Jsoup.parse(item.getCrsSummary()).text(); String courseNumber = parseCourseNumber(item.getCrsKorNm()); - return new CourseRequestDTO( + return new CourseRequest( item.getCrsKorNm(), Integer.parseInt(item.getCrsDstnc()), Integer.parseInt(item.getCrsTotlRqrmHour()), From a0db5ffeb89ad1402fa3a0c01168c9dee5afb3f5 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:44:26 +0900 Subject: [PATCH 11/31] =?UTF-8?q?feat:=20current=20=EB=82=A0=EC=94=A8=20AP?= =?UTF-8?q?I=20URI=20=EC=83=9D=EC=84=B1=20=EC=B6=94=EA=B0=80=20-=20=20Craw?= =?UTF-8?q?lApiBuilderHelper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/helper/CrawlApiBuilderHelper.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java index ab814d15..95604601 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java @@ -1,16 +1,21 @@ package com.hubo.gillajabi.crawl.infrastructure.util.helper; -import com.hubo.gillajabi.crawl.infrastructure.config.ApiProperties; +import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; import org.springframework.stereotype.Component; import java.net.URI; import java.net.URISyntaxException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; @Component public class CrawlApiBuilderHelper { - public URI buildUri(final String endpointPath, final ApiProperties apiProperties, final int pageNo, final int numOfRows) { + private static final int numOfRows = 100; + + + public URI buildUri(final String endpointPath, final ApiProperties apiProperties, final int pageNo) { try { final String url = apiProperties.getSiteUrl() .replace("{}", endpointPath) @@ -23,6 +28,33 @@ public URI buildUri(final String endpointPath, final ApiProperties apiProperties } } + /** + * current 날씨 API URI 생성 입니다. + * + * @param apiProperties + * @param pageNo : 페이지 번호 + * @param nx : x 좌표 + * @param ny : y 좌표 + * @param baseDate : 기준 날짜 + * @return + */ + public URI buildUri(final ApiProperties apiProperties, final int nx, final int ny, final LocalDate baseDate, final int pageNo) { + try { + String baseDateStr = baseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + final String url = apiProperties.getSiteUrl() + .replace("{serviceKey}", apiProperties.getEncoding()) + .replace("{numOfRows}", String.valueOf(numOfRows)) + .replace("{pageNo}", String.valueOf(pageNo)) + .replace("{baseDate}", baseDateStr) + .replace("{nx}", String.valueOf(nx)) + .replace("{ny}", String.valueOf(ny)); + return new URI(url); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("URI 생성 실패: " + e.getMessage(), e); + } + } + + public void validateResponse(ValidatableResponse response) { response.validate(); } From 12b4139f603c5cf6b8b3099b9c993c4fbc9bc22b Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:44:51 +0900 Subject: [PATCH 12/31] =?UTF-8?q?feat:=20CrawlExceptionCode=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawl/infrastructure/exception/CrawlExceptionCode.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/exception/CrawlExceptionCode.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/exception/CrawlExceptionCode.java index 9926e439..ae9cbb9a 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/exception/CrawlExceptionCode.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/exception/CrawlExceptionCode.java @@ -7,7 +7,9 @@ public enum CrawlExceptionCode { UNSIGNED_CALL_ERROR(33, "서명되지 않은 호출"), SERVICETIMEOUT_ERROR(5, "서비스 연결 실패 에러"), NODATA_ERROR(3, "데이터 없음 에러"), - DB_ERROR(2, "데이터베이스 에러"); + DB_ERROR(2, "데이터베이스 에러"), + //파싱 실패 에러 + PARSING_ERROR(4, "파싱 실패 에러"); private final int code; private final String message; From c5a68820f36d61d4ebf1b1c5c42574b407c8ef9c Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:52:43 +0900 Subject: [PATCH 13/31] =?UTF-8?q?feat:=20weather=20currentCrawl=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/service/WeatherCrawlService.java | 9 ++ .../service/WeatherCrawlServiceImpl.java | 106 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlService.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlService.java new file mode 100644 index 00000000..a258f0b2 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlService.java @@ -0,0 +1,9 @@ +package com.hubo.gillajabi.crawl.domain.service; + +public interface WeatherCrawlService { + + void currentCrawl(); + void alertCrawl(); + void weatherMediumTermCrawl(); + +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java new file mode 100644 index 00000000..5df6333f --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java @@ -0,0 +1,106 @@ +package com.hubo.gillajabi.crawl.domain.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hubo.gillajabi.crawl.domain.constant.ForecastType; +import com.hubo.gillajabi.crawl.domain.constant.WeatherRedisConstants; +import com.hubo.gillajabi.crawl.domain.entity.City; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.WeatherDto; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiWeatherCurrentResponse; +import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; +import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; +import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; +import com.hubo.gillajabi.global.common.dto.ApiProperties; +import com.hubo.gillajabi.crawl.infrastructure.config.WeatherEndpointConfig; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.net.URI; +import java.time.LocalDate; +import java.util.*; + + +@Service +@RequiredArgsConstructor +@Transactional +@Slf4j +public class WeatherCrawlServiceImpl implements WeatherCrawlService { + + private static Map weatherApiProperties; + + private final WeatherEndpointConfig weatherEndpointConfig; + private final CrawlApiBuilderHelper crawlApiBuilderHelper; + private final GenericCrawlerService genericCrawlerService; + private final CityRepository cityRepository; + private final StringRedisTemplate stringRedisTemplate; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @PostConstruct + private void init() { + weatherApiProperties = weatherEndpointConfig.getEndPoint(); + validateWeatherApiProperties(); + } + + private void validateWeatherApiProperties() { + if (weatherApiProperties == null) { + throw new IllegalStateException("Weather Crawl Service 가 초기화 되지 않았습니다."); + } + } + + public void currentCrawl() { + List cities = cityRepository.findAll(); + cities.forEach(city -> { + LocalDate date = LocalDate.now(); + try { + List currentWeatherData = crawlWeatherData(city); + processWeatherData(city, date, currentWeatherData); + } catch (Exception e) { + log.info("날씨 데이터 수집 중 오류 발생: " + e.getMessage()); + } + }); + } + + private List crawlWeatherData(City city) { + LocalDate targetDate = LocalDate.now(); + + GenericCrawlerService.CrawlPageFunction function = pageNo -> { + URI uri = crawlApiBuilderHelper.buildUri(weatherApiProperties.get(ForecastType.CURRENT), city.getNx(), city.getNy(), targetDate, pageNo); + return genericCrawlerService.crawlPage(ApiWeatherCurrentResponse.class, uri); + }; + + return genericCrawlerService.crawlItems(function); + } + + private void processWeatherData(City city, LocalDate date, List currentWeatherData) { + Map weatherDataByTime = new HashMap<>(); + for (ApiWeatherCurrentResponse.Current current : currentWeatherData) { + WeatherDto weatherDto = weatherDataByTime.computeIfAbsent(current.getFcstTime(), k -> new WeatherDto()); + weatherDto.updateWeatherDtoFromCurrent(current); + } + + weatherDataByTime.forEach((baseTime, weatherDto) -> { + try { + String key = WeatherRedisConstants.makeWeatherKey(city, date, baseTime); + String value = objectMapper.writeValueAsString(weatherDto); + stringRedisTemplate.opsForValue().set(key, value); + } catch (Exception e) { + throw new CrawlException(2, "날씨 데이터 저장 오류: " + e.getMessage()); + } + }); + } + + @Override + public void weatherMediumTermCrawl() { + System.out.println("Weather Medium Term Crawl"); + } + + @Override + public void alertCrawl() { + System.out.println("Weather Alert Crawl"); + } +} + From 4f35dc3397a784f2078719ff82344d5db0504631 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:53:48 +0900 Subject: [PATCH 14/31] =?UTF-8?q?refactor:=20=EB=B3=80=EA=B2=BD=EB=90=9C?= =?UTF-8?q?=20CityCrawlName=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/config/RoadEndpointConfig.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java index 1c155732..7d3d51ac 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/config/RoadEndpointConfig.java @@ -1,9 +1,8 @@ package com.hubo.gillajabi.crawl.infrastructure.config; import com.hubo.gillajabi.global.common.dto.ApiProperties; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import lombok.Getter; -import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -13,13 +12,12 @@ @Configuration @ConfigurationProperties(prefix = "road") -@Slf4j @Getter public class RoadEndpointConfig { - private final Map roadEndpoints = new EnumMap<>(CityName.class); + private final Map roadEndpoints = new EnumMap<>(CityCrawlName.class); - public ApiProperties getEndpoint(CityName cityName) { - return roadEndpoints.get(cityName); + public ApiProperties getEndpoint(CityCrawlName cityCrawlName) { + return roadEndpoints.get(cityCrawlName); } } From 234f1bd3fa9d0cff3acb34a1576e2ec5eecbd1d4 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 00:55:16 +0900 Subject: [PATCH 15/31] =?UTF-8?q?refactor:=20handler=20domain=20=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RoadCrawlFacadeService.java | 14 +++++--- .../service/busan}/RoadBusanThemeHandler.java | 2 +- .../busan}/RoadCrawlBusanCourseHandler.java | 2 +- .../service/duru}/RoadDuruCourseHandler.java | 3 +- .../service/duru}/RoadDuruThemeHandler.java | 2 +- .../service/RoadCrawlFacadeServiceTest.java | 14 +++++--- .../service/RoadDuruCourseHandlerTest.java | 32 +++++++++---------- 7 files changed, 37 insertions(+), 32 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/{application/service => domain/service/busan}/RoadBusanThemeHandler.java (85%) rename src/main/java/com/hubo/gillajabi/crawl/{application/service => domain/service/busan}/RoadCrawlBusanCourseHandler.java (82%) rename src/main/java/com/hubo/gillajabi/crawl/{application/service => domain/service/duru}/RoadDuruCourseHandler.java (93%) rename src/main/java/com/hubo/gillajabi/crawl/{application/service => domain/service/duru}/RoadDuruThemeHandler.java (94%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java index 31091c41..38a4e3c0 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java @@ -2,7 +2,11 @@ import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; +import com.hubo.gillajabi.crawl.domain.service.busan.RoadBusanThemeHandler; +import com.hubo.gillajabi.crawl.domain.service.busan.RoadCrawlBusanCourseHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,15 +20,15 @@ public class RoadCrawlFacadeService { private final RoadDuruThemeHandler roadDuruThemeHandler; private final RoadBusanThemeHandler roadBusanThemeHandler; - public RoadCrawlResponse.CourseResult getCourse(final CityName cityName) { - return switch (cityName) { + public RoadCrawlResponse.CourseResult getCourse(final CityCrawlName cityCrawlName) { + return switch (cityCrawlName) { case DURU -> roadDuruCourseHandler.handle(); case BUSAN -> roadCrawlBusanCourseHandler.handle(); }; } - public RoadCrawlResponse.ThemeResult getTheme(final CityName cityName) { - return switch (cityName) { + public RoadCrawlResponse.ThemeResult getTheme(final CityCrawlName cityCrawlName) { + return switch (cityCrawlName) { case DURU -> roadDuruThemeHandler.handle(); case BUSAN -> roadBusanThemeHandler.handle(); }; diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadBusanThemeHandler.java similarity index 85% rename from src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadBusanThemeHandler.java index fe00c834..f58123ed 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadBusanThemeHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadBusanThemeHandler.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.crawl.domain.service.busan; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanCourseHandler.java similarity index 82% rename from src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanCourseHandler.java index fc8b4c61..a34eb1c6 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlBusanCourseHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanCourseHandler.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.crawl.domain.service.busan; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java similarity index 93% rename from src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java index 8ba918e0..1bbe4144 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruCourseHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java @@ -1,11 +1,10 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; -import com.hubo.gillajabi.crawl.domain.service.duru.*; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java similarity index 94% rename from src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java index af3f27cb..12620f59 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadDuruThemeHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.crawl.application.service; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java index ecf07737..c92d22c0 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java @@ -5,7 +5,11 @@ import com.hubo.gillajabi.crawl.application.service.*; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; +import com.hubo.gillajabi.crawl.domain.service.busan.RoadBusanThemeHandler; +import com.hubo.gillajabi.crawl.domain.service.busan.RoadCrawlBusanCourseHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -44,7 +48,7 @@ public void testGetDuruCourse() { when(roadDuruCourseHandler.handle()).thenReturn(duruCourseResult); // when - assertEquals(duruCourseResult, roadCrawlFacadeService.getCourse(CityName.DURU)); + assertEquals(duruCourseResult, roadCrawlFacadeService.getCourse(CityCrawlName.DURU)); // then verify(roadDuruCourseHandler).handle(); @@ -61,7 +65,7 @@ public void testGetBusanCourse() { when(roadCrawlBusanCourseHandler.handle()).thenReturn(busanCourseResult); // when - assertEquals(busanCourseResult, roadCrawlFacadeService.getCourse(CityName.BUSAN)); + assertEquals(busanCourseResult, roadCrawlFacadeService.getCourse(CityCrawlName.BUSAN)); // then verify(roadCrawlBusanCourseHandler).handle(); @@ -78,7 +82,7 @@ public void testGetDuruTheme() { when(roadDuruThemeHandler.handle()).thenReturn(duruThemeResult); // when - assertEquals(duruThemeResult, roadCrawlFacadeService.getTheme(CityName.DURU)); + assertEquals(duruThemeResult, roadCrawlFacadeService.getTheme(CityCrawlName.DURU)); // then verify(roadDuruThemeHandler).handle(); @@ -95,7 +99,7 @@ public void testGetBusanTheme() { when(roadBusanThemeHandler.handle()).thenReturn(busanThemeResult); // when - assertEquals(busanThemeResult, roadCrawlFacadeService.getTheme(CityName.BUSAN)); + assertEquals(busanThemeResult, roadCrawlFacadeService.getTheme(CityCrawlName.BUSAN)); // then verify(roadBusanThemeHandler).handle(); diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java index 955ee3fc..b31e781e 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java @@ -1,17 +1,15 @@ package com.hubo.gillajabi.road.application.service; -import com.hubo.gillajabi.crawl.application.service.RoadDuruCourseHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.*; import com.hubo.gillajabi.crawl.domain.service.duru.*; -import com.hubo.gillajabi.road.domain.entity.*; -import com.hubo.gillajabi.road.domain.service.road.duru.*; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; @@ -62,26 +60,26 @@ public ApiCourseResponse.Course createDuruCourseResponse(){ return response; } private static CourseDetail createCourseDetail() { - CourseDetailRequestDTO courseDetailRequestDTO = fixtureMonkey.giveMeOne(CourseDetailRequestDTO.class); - return CourseDetail.createCourseDetail(courseDetailRequestDTO); + CourseDetailRequest courseDetailRequest = fixtureMonkey.giveMeOne(CourseDetailRequest.class); + return CourseDetail.createCourseDetail(courseDetailRequest); } private static Course createCourse(ApiCourseResponse.Course mockCourseDuruResponse, City mockCity, CourseTheme mockCourseTheme) { - CourseRequestDTO courseRequestDTO = CourseRequestDTO.of(mockCourseDuruResponse, mockCity, mockCourseTheme); - courseRequestDTO.setCity(mockCity); - courseRequestDTO.setLevel(CourseLevel.fromValue(mockCourseDuruResponse.getCrsLevel())); + CourseRequest courseRequest = CourseRequest.of(mockCourseDuruResponse, mockCity, mockCourseTheme); + courseRequest.setCity(mockCity); + courseRequest.setLevel(CourseLevel.fromValue(mockCourseDuruResponse.getCrsLevel())); - return Course.createCourse(courseRequestDTO); + return Course.createCourse(courseRequest); } private static CourseTheme createCourseTheme() { - CourseThemeRequestDTO courseThemeRequestDTO = fixtureMonkey.giveMeOne(CourseThemeRequestDTO.class); - return CourseTheme.createCourseTheme(courseThemeRequestDTO); + CourseThemeRequest courseThemeRequest = fixtureMonkey.giveMeOne(CourseThemeRequest.class); + return CourseTheme.createCourseTheme(courseThemeRequest); } private static City createCity(ApiCourseResponse.Course mockCourseDuruResponse) { - CityRequestDTO cityRequestDTO = CityRequestDTO.of(mockCourseDuruResponse.getCrsKorNm(), Province.GYEONGGI, "짧은소개글"); - return City.createCity(cityRequestDTO); + CityRequest cityRequest = CityRequest.of(mockCourseDuruResponse.getCrsKorNm(), Province.GYEONGGI, "짧은소개글"); + return City.createCity(cityRequest); } private void mockDuruHandle() { From 3f40e25811414df901df00b2b1ec97ac263188a1 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:39:46 +0900 Subject: [PATCH 16/31] =?UTF-8?q?feat:=20=EB=82=A0=EC=94=A8=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20api=EC=97=90=20=EB=8C=80=EC=9D=91=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20-=20CrawlApiBuilderHelper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/helper/CrawlApiBuilderHelper.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java index 95604601..425b425f 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/util/helper/CrawlApiBuilderHelper.java @@ -1,5 +1,6 @@ package com.hubo.gillajabi.crawl.infrastructure.util.helper; +import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; import org.springframework.stereotype.Component; @@ -12,7 +13,7 @@ @Component public class CrawlApiBuilderHelper { - private static final int numOfRows = 100; + private static final String numOfRows = "100"; public URI buildUri(final String endpointPath, final ApiProperties apiProperties, final int pageNo) { @@ -20,7 +21,7 @@ public URI buildUri(final String endpointPath, final ApiProperties apiProperties final String url = apiProperties.getSiteUrl() .replace("{}", endpointPath) .replace("{serviceKey}", apiProperties.getEncoding()) - .replace("{numOfRows}", String.valueOf(numOfRows)) + .replace("{numOfRows}", numOfRows) .replace("{pageNo}", String.valueOf(pageNo)); return new URI(url); } catch (URISyntaxException e) { @@ -28,6 +29,35 @@ public URI buildUri(final String endpointPath, final ApiProperties apiProperties } } + + /** + * MEDIUM_TERM 날씨 API URI 생성 입니다. + * + * @param endPointPath : 어떤 API 를 호출할지 + * @param apiProperties : API 정보 + * @param pageNo : 페이지 번호 + * @param city : 도시 + * @param date : 검색 기준 날짜 + * @return URI + */ + public URI buildUri(final String endPointPath, final ApiProperties apiProperties, final City city, final int pageNo, final LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + String formattedDate = date.format(formatter) + "0600"; + + try { + final String url = apiProperties.getSiteUrl() + .replace("{endPath}", endPointPath) + .replace("{serviceKey}", apiProperties.getEncoding()) + .replace("{numOfRows}", numOfRows) + .replace("{pageNo}", String.valueOf(pageNo)) + .replace("{cityCode}", city.getCityCode()) + .replace("{tmFc}", formattedDate); + return new URI(url); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("URI 생성 실패: " + e.getMessage(), e); + } + } + /** * current 날씨 API URI 생성 입니다. * @@ -43,7 +73,7 @@ public URI buildUri(final ApiProperties apiProperties, final int nx, final int n String baseDateStr = baseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")); final String url = apiProperties.getSiteUrl() .replace("{serviceKey}", apiProperties.getEncoding()) - .replace("{numOfRows}", String.valueOf(numOfRows)) + .replace("{numOfRows}", numOfRows) .replace("{pageNo}", String.valueOf(pageNo)) .replace("{baseDate}", baseDateStr) .replace("{nx}", String.valueOf(nx)) From b2241498a9dc240f3bfdfce82231eff45797fa76 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:40:33 +0900 Subject: [PATCH 17/31] =?UTF-8?q?feat:=20redis=20=EC=BF=BC=EB=A6=AC?= =?UTF-8?q?=EB=8F=84=20=EB=A1=9C=EA=B9=85=20=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hubo/gillajabi/global/common/aop/QueryCounterAop.java | 7 +++++++ .../hubo/gillajabi/global/common/dto/LoggingFormat.java | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/com/hubo/gillajabi/global/common/aop/QueryCounterAop.java b/src/main/java/com/hubo/gillajabi/global/common/aop/QueryCounterAop.java index 7b42f238..7b641bf2 100644 --- a/src/main/java/com/hubo/gillajabi/global/common/aop/QueryCounterAop.java +++ b/src/main/java/com/hubo/gillajabi/global/common/aop/QueryCounterAop.java @@ -37,6 +37,13 @@ private LoggingFormat getCurrentLoggingForm() { return currentLoggingForm.get(); } + @Around("execution(* org.springframework.data.redis.core.RedisTemplate.*(..))") + public Object captureRedis(final ProceedingJoinPoint joinPoint) throws Throwable { + final Object result = joinPoint.proceed(); + getCurrentLoggingForm().redisQueryCountUp(); + return result; + } + @Around("within(@org.springframework.web.bind.annotation.RestController *)") public Object logExecutionTime(final ProceedingJoinPoint joinPoint) throws Throwable { final long startTime = System.currentTimeMillis(); diff --git a/src/main/java/com/hubo/gillajabi/global/common/dto/LoggingFormat.java b/src/main/java/com/hubo/gillajabi/global/common/dto/LoggingFormat.java index 0c6817bd..07ce4de3 100644 --- a/src/main/java/com/hubo/gillajabi/global/common/dto/LoggingFormat.java +++ b/src/main/java/com/hubo/gillajabi/global/common/dto/LoggingFormat.java @@ -16,6 +16,8 @@ public class LoggingFormat { private Long queryTime = 0L; + private Long redisQueryCounts = 0L; + private HttpStatus statusCode; private Long executionTime; @@ -36,6 +38,10 @@ public void addQueryTime(final Long queryTime) { this.queryTime += queryTime; } + public void redisQueryCountUp() { + redisQueryCounts++; + } + public void setStatusCode(final int statusCode) { this.statusCode = HttpStatus.valueOf(statusCode); } From 1de803db6f67901b0a0fa5a697fedb51a77dd7fc Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:40:59 +0900 Subject: [PATCH 18/31] =?UTF-8?q?feat:=20RedisConfig=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/common/config/RedisConfig.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/global/common/config/RedisConfig.java diff --git a/src/main/java/com/hubo/gillajabi/global/common/config/RedisConfig.java b/src/main/java/com/hubo/gillajabi/global/common/config/RedisConfig.java new file mode 100644 index 00000000..890f72bc --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/global/common/config/RedisConfig.java @@ -0,0 +1,40 @@ +package com.hubo.gillajabi.global.common.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +@EnableRedisRepositories +public class RedisConfig { + + @Value("${spring.data.redis.host}") + private String host; + + @Value("${spring.data.redis.port}") + private int port; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } + + @Bean + public RedisTemplate redisTemplate(ObjectMapper objectMapper) { + final RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + + redisTemplate.setKeySerializer(new StringRedisSerializer()); + + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class); + redisTemplate.setValueSerializer(serializer); + + return redisTemplate; + } +} From d40ed9e5ed5db9e676469a4a77f9e27a6178ccf9 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:41:29 +0900 Subject: [PATCH 19/31] =?UTF-8?q?feat:=20MediumTermSkyCondition=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constant/MediumTermSkyCondition.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java new file mode 100644 index 00000000..ed1749ec --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java @@ -0,0 +1,47 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +public enum MediumTermSkyCondition { + // 맑음 + CLEAR("맑음"), + + // 구름많음, 구름많고 비, 구름많고 눈, 구름많고 비/눈, 구름많고 소나기 + MOSTLY_CLOUDY("구름많음"), + MOSTLY_CLOUDY_WITH_RAIN("구름많고 비"), + MOSTLY_CLOUDY_WITH_SNOW("구름많고 눈"), + MOSTLY_CLOUDY_WITH_RAIN_AND_SNOW("구름많고 비/눈"), + MOSTLY_CLOUDY_WITH_SHOWERS("구름많고 소나기"), + + // 흐림, 흐리고 비, 흐리고 눈, 흐리고 비/눈, 흐리고 소나기 + CLOUDY("흐림"), + CLOUDY_WITH_RAIN("흐리고 비"), + CLOUDY_WITH_SNOW("흐리고 눈"), + CLOUDY_WITH_RAIN_AND_SNOW("흐리고 비/눈"), + CLOUDY_WITH_SHOWERS("흐리고 소나기"); + + private final String description; + + MediumTermSkyCondition(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + + public static MediumTermSkyCondition fromString(String value){ + return switch (value) { + case "맑음" -> CLEAR; + case "구름많음" -> MOSTLY_CLOUDY; + case "구름많고 비" -> MOSTLY_CLOUDY_WITH_RAIN; + case "구름많고 눈" -> MOSTLY_CLOUDY_WITH_SNOW; + case "구름많고 비/눈" -> MOSTLY_CLOUDY_WITH_RAIN_AND_SNOW; + case "구름많고 소나기" -> MOSTLY_CLOUDY_WITH_SHOWERS; + case "흐림" -> CLOUDY; + case "흐리고 비" -> CLOUDY_WITH_RAIN; + case "흐리고 눈" -> CLOUDY_WITH_SNOW; + case "흐리고 비/눈" -> CLOUDY_WITH_RAIN_AND_SNOW; + case "흐리고 소나기" -> CLOUDY_WITH_SHOWERS; + default -> throw new IllegalArgumentException("잘못된 하늘 상태 : " + value); + }; + } +} From 18e2095ad96a02f94eb341ba1a780bdb8936b247 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:42:32 +0900 Subject: [PATCH 20/31] =?UTF-8?q?refactor:=20roadCrawl=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presenation/RoadCrawlController.java | 10 +-- .../duru/RoadCrawlDuruServiceImpl.java | 85 +++---------------- .../service/duru/RoadGpxInfoDuruService.java | 10 +-- .../service/RoadDuruThemeHandlerTest.java | 6 +- .../duru/RoadGpxInfoDuruServiceTest.java | 29 +++---- .../config/RoadEndpointConfigTest.java | 6 +- 6 files changed, 43 insertions(+), 103 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java index 7346f6b4..11774a8b 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java +++ b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/RoadCrawlController.java @@ -3,7 +3,7 @@ import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.application.service.RoadCrawlFacadeService; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -21,18 +21,18 @@ public class RoadCrawlController { @Operation(summary = "전국 길 크롤링 ", description = "만약 해당 정보가 존재한다면 생략합니다.") @PostMapping("/courses") - public ResponseEntity startCrawlingCurse(@Valid @RequestParam CityName cityName) { + public ResponseEntity startCrawlingCurse(@Valid @RequestParam CityCrawlName cityCrawlName) { - RoadCrawlResponse.CourseResult response = roadCrawlFacadeService.getCourse(cityName); + RoadCrawlResponse.CourseResult response = roadCrawlFacadeService.getCourse(cityCrawlName); return ResponseEntity.ok().body(response); } @Operation(summary = "전국 길 테마 크롤링", description = "전국 길 테마 크롤링 (ex: 남파랑길)") @PostMapping("/themes") - public ResponseEntity startCrawlingTheme(@Valid @RequestParam CityName cityName) { + public ResponseEntity startCrawlingTheme(@Valid @RequestParam CityCrawlName cityCrawlName) { - RoadCrawlResponse.ThemeResult response = roadCrawlFacadeService.getTheme(cityName); + RoadCrawlResponse.ThemeResult response = roadCrawlFacadeService.getTheme(cityCrawlName); return ResponseEntity.ok().body(response); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java index 389daef8..0dd777fe 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java @@ -1,26 +1,19 @@ package com.hubo.gillajabi.crawl.domain.service.duru; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.hubo.gillajabi.crawl.domain.constant.CityName; -import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; +import com.hubo.gillajabi.crawl.domain.service.GenericCrawlerService; import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractApiResponse; import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.hubo.gillajabi.global.common.dto.ApiProperties; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; -import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jsoup.Jsoup; import org.springframework.stereotype.Service; import java.net.URI; -import java.util.ArrayList; import java.util.List; @Service @@ -30,92 +23,40 @@ public class RoadCrawlDuruServiceImpl extends RoadAbstractCrawlDuruService { private final RoadEndpointConfig roadEndpointConfig; private final CrawlApiBuilderHelper crawlApiBuilderHelper; - private final ResponseCrawlService responseCrawlService; - + private final GenericCrawlerService genericCrawlerService; private static ApiProperties duruApiProperties; - private static final ObjectMapper objectMapper = new ObjectMapper(); - - private static final int numOfRows = 100; - @PostConstruct private void init() { - this.duruApiProperties = roadEndpointConfig.getEndpoint(CityName.DURU); + duruApiProperties = roadEndpointConfig.getEndpoint(CityCrawlName.DURU); validateDuruApiProperties(); } private void validateDuruApiProperties() { - if (this.duruApiProperties == null) { + if (duruApiProperties == null) { throw new IllegalStateException("DURU Crawl Service가 초기화 되지 않았습니다."); } } @Override public List crawlCourse() { - return crawlItems(this::crawlCoursePage); + return genericCrawlerService.crawlItems(this::crawlCoursePage); } @Override public List crawlTheme() { - List themes = crawlItems(this::crawlThemePage); - themes.forEach(theme -> theme.setThemedescs(Jsoup.parse(theme.getThemedescs()).text())); - return themes; + return genericCrawlerService.crawlItems(this::crawlThemePage); } - private List crawlItems(final CrawlPageFunction crawlPageFunction){ - int pageNo = 1; - List allItems = new ArrayList<>(); - - while (true) { - try { - List items = crawlPageFunction.crawlPage(pageNo); - if (items.isEmpty()) { - break; - } - allItems.addAll(items); - pageNo++; - } catch (Exception e) { - throw new CrawlException(500, "공공데이터 DURU 호출 중 예기치 못한 오류 발생 :" + e.getMessage()); - } - } - return allItems; + private AbstractApiResponse crawlCoursePage(int pageNo) throws Exception { + URI uri = crawlApiBuilderHelper.buildUri("courseList", duruApiProperties, pageNo); + return genericCrawlerService.crawlPage(ApiCourseResponse.class, uri); } - private List getItems(AbstractApiResponse.Body body) { - if (body == null || body.getItems() == null || body.getItems().getItem() == null) { - return new ArrayList<>(); - } - return body.getItems().getItem(); + private AbstractApiResponse crawlThemePage(int pageNo) throws Exception { + URI uri = crawlApiBuilderHelper.buildUri("routeList", duruApiProperties, pageNo); + return genericCrawlerService.crawlPage(ApiThemeResponse.class, uri); } - private List crawlCoursePage(final int pageNo) throws JsonProcessingException { - ApiCourseResponse.Body body = - crawlPage(pageNo, "courseList", ApiCourseResponse.class).getResponse().getBody(); - return getItems(body); - } - private List crawlThemePage(final int pageNo) throws JsonProcessingException { - ApiThemeResponse.Body body = - crawlPage(pageNo, "routeList", ApiThemeResponse.class).getResponse().getBody(); - return getItems(body); - } - - - private T crawlPage(final int pageNo, final String endpoint, Class responseType) throws JsonProcessingException { - final URI uri = buildUri(endpoint, pageNo); - final String response = responseCrawlService.fetchApiResponse(uri); - objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true); - final T parsedResponse = objectMapper.readValue(response, responseType); - crawlApiBuilderHelper.validateResponse(parsedResponse); - return parsedResponse; - } - - private URI buildUri(final String endpoint, final int pageNo) { - return crawlApiBuilderHelper.buildUri(endpoint, duruApiProperties, pageNo, numOfRows); - } - - @FunctionalInterface - private interface CrawlPageFunction { - List crawlPage(int pageNo) throws JsonProcessingException; - } } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java index 727a66e3..4fc82adb 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java @@ -6,7 +6,7 @@ import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruGpxResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiDuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; import lombok.RequiredArgsConstructor; @@ -52,7 +52,7 @@ private GpxInfo processCourseDetailAndSave(CourseDetail courseDetail) throws IOE return null; } - DuruGpxResponse gpxResponse = fetchGpxResponse(courseDetail.getGpxPath()); + ApiDuruGpxResponse gpxResponse = fetchGpxResponse(courseDetail.getGpxPath()); String jsonGpx = convertToJson(gpxResponse); return saveGpxInfo(jsonGpx, courseDetail); } @@ -61,13 +61,13 @@ private boolean shouldSkip(String path) { return path.endsWith(".kmz"); } - private DuruGpxResponse fetchGpxResponse(String gpxUrl) throws IOException { + private ApiDuruGpxResponse fetchGpxResponse(String gpxUrl) throws IOException { URI uri = URI.create(gpxUrl); String response = responseCrawlService.fetchApiResponse(uri); - return xmlMapper.readValue(response, DuruGpxResponse.class); + return xmlMapper.readValue(response, ApiDuruGpxResponse.class); } - private String convertToJson(DuruGpxResponse gpxResponse) throws JsonProcessingException { + private String convertToJson(ApiDuruGpxResponse gpxResponse) throws JsonProcessingException { return jsonMapper.writeValueAsString(gpxResponse); } diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java index dc4c8da6..efbafe38 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java @@ -1,11 +1,11 @@ package com.hubo.gillajabi.road.application.service; -import com.hubo.gillajabi.crawl.application.service.RoadDuruThemeHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruThemeService; import com.hubo.gillajabi.crawl.domain.service.duru.RoadCrawlDuruServiceImpl; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; @@ -45,7 +45,7 @@ void testHandle() { // CourseTheme 생성 List mockThemes = mockResponseItems.stream() .map(theme -> CourseTheme.createCourseTheme( - new CourseThemeRequestDTO(theme.getThemeNm(), theme.getLinemsg(), theme.getThemedescs()))) + new CourseThemeRequest(theme.getThemeNm(), theme.getLinemsg(), theme.getThemedescs()))) .collect(Collectors.toList()); when(duruCrawlService.crawlTheme()).thenReturn(mockResponseItems); diff --git a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java index 544030bd..2b6c125c 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java @@ -7,10 +7,9 @@ import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; import com.hubo.gillajabi.crawl.domain.service.duru.RoadGpxInfoDuruService; -import com.hubo.gillajabi.road.domain.entity.*; import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.response.DuruGpxResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiDuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.BeforeEach; @@ -46,17 +45,17 @@ class RoadGpxInfoDuruServiceTest { @BeforeEach public void setUp() { - CourseDetailRequestDTO courseDetailRequestDTO = fixtureMonkey.giveMeOne(CourseDetailRequestDTO.class); - courseDetailRequestDTO.setGpxPath("http://gpxpath.com.kmz"); + CourseDetailRequest courseDetailRequest = fixtureMonkey.giveMeOne(CourseDetailRequest.class); + courseDetailRequest.setGpxPath("http://gpxpath.com.kmz"); } public void mockApiResponseService() throws JsonProcessingException { // 외부 의존성을 모킹한다 - DuruGpxResponse duruGpxResponse = fixtureMonkey.giveMeOne(DuruGpxResponse.class); + ApiDuruGpxResponse apiDuruGpxResponse = fixtureMonkey.giveMeOne(ApiDuruGpxResponse.class); // XML로 변환 XmlMapper xmlMapper = new XmlMapper(); - String xmlResponse = xmlMapper.writeValueAsString(duruGpxResponse); + String xmlResponse = xmlMapper.writeValueAsString(apiDuruGpxResponse); // API 응답을 모킹 when(responseCrawlService.fetchApiResponse(any(URI.class))) @@ -67,12 +66,12 @@ public void mockApiResponseService() throws JsonProcessingException { @DisplayName("List를 받아서 새로운 GpxInfo 객체를 생성하고 저장한다.") public void testSaveGpxInfoWithValidCourseDetails() throws JsonProcessingException { // given - List requestDTOs = new ArrayList<>(); + List requestDTOs = new ArrayList<>(); - CourseDetailRequestDTO courseDetailRequestDTO = fixtureMonkey.giveMeOne(CourseDetailRequestDTO.class); - courseDetailRequestDTO.setGpxPath("http://gpxpath.com"); + CourseDetailRequest courseDetailRequest = fixtureMonkey.giveMeOne(CourseDetailRequest.class); + courseDetailRequest.setGpxPath("http://gpxpath.com"); - requestDTOs.add(courseDetailRequestDTO); + requestDTOs.add(courseDetailRequest); List mockCourseDetails = requestDTOs.stream() .map(CourseDetail::createCourseDetail) @@ -92,12 +91,12 @@ public void testSaveGpxInfoWithValidCourseDetails() throws JsonProcessingExcepti @DisplayName("gpxPath가 kmz로 끝나는 경우 패스한다") public void gpxPath가_kmz로_끝나는_경우() { //given - List requestDTOs = new ArrayList<>(); + List requestDTOs = new ArrayList<>(); - CourseDetailRequestDTO courseDetailRequestDTO = fixtureMonkey.giveMeOne(CourseDetailRequestDTO.class); - courseDetailRequestDTO.setGpxPath("http://gpxpath.com.kmz"); + CourseDetailRequest courseDetailRequest = fixtureMonkey.giveMeOne(CourseDetailRequest.class); + courseDetailRequest.setGpxPath("http://gpxpath.com.kmz"); - requestDTOs.add(courseDetailRequestDTO); + requestDTOs.add(courseDetailRequest); List mockCourseDetails = requestDTOs.stream() .map(CourseDetail::createCourseDetail) diff --git a/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java b/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java index 0c71b28f..c9d3f506 100644 --- a/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java +++ b/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java @@ -1,6 +1,6 @@ package com.hubo.gillajabi.road.infraStructure.config; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import com.hubo.gillajabi.global.common.dto.ApiProperties; import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; import org.junit.jupiter.api.DisplayName; @@ -21,14 +21,14 @@ class RoadEndpointConfigTest { @Test @DisplayName("road-yml에 정의된 road를 올바르게 읽어온다.") void testRoadProperties() { - ApiProperties duruProperties = roadEndpointConfig.getEndpoint(CityName.DURU); + ApiProperties duruProperties = roadEndpointConfig.getEndpoint(CityCrawlName.DURU); assertThat(duruProperties).isNotNull(); assertThat(duruProperties.getEndpoint()).isEqualTo("http://example.com"); assertThat(duruProperties.getEncoding()).isEqualTo("serviceKey"); assertThat(duruProperties.getDecoding()).isEqualTo("serviceKey"); assertThat(duruProperties.getSiteUrl()).isEqualTo("http://example.com"); - ApiProperties busanProperties = roadEndpointConfig.getEndpoint(CityName.BUSAN); + ApiProperties busanProperties = roadEndpointConfig.getEndpoint(CityCrawlName.BUSAN); assertThat(busanProperties).isNotNull(); assertThat(busanProperties.getEndpoint()).isEqualTo("http://example.com"); assertThat(busanProperties.getEncoding()).isEqualTo("serviceKey"); From f8b726039335041409108b31074b3156795b8b46 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Thu, 27 Jun 2024 17:44:14 +0900 Subject: [PATCH 21/31] =?UTF-8?q?feat:=20=EB=82=A0=EC=94=A8=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20dto=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constant/WeatherRedisConstants.java | 28 +++++ .../dto/request/WeatherCurrentDto.java | 108 ++++++++++++++++++ .../dto/request/WeatherTermDTO.java | 47 ++++++++ 3 files changed, 183 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstants.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherCurrentDto.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstants.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstants.java new file mode 100644 index 00000000..17dc1f78 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstants.java @@ -0,0 +1,28 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import com.hubo.gillajabi.crawl.domain.entity.City; +import jakarta.annotation.Nullable; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class WeatherRedisConstants { + + private static final String WEATHER_API_RESPONSE = "weather:"; + private static final String WILD_CARD = "*"; + + /** + * redis key 생성 + * @param city + * @param date + * @param baseTime @Nullable + * @return key + */ + public static String makeWeatherKey(final City city, final LocalDate date, @Nullable final String baseTime) { + final String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + if (baseTime == null) { + return WEATHER_API_RESPONSE + city.getName() + ":" + dateStr; + } + return WEATHER_API_RESPONSE + city.getName() + ":" + dateStr + ":" + baseTime; + } +} diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherCurrentDto.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherCurrentDto.java new file mode 100644 index 00000000..c91f431c --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherCurrentDto.java @@ -0,0 +1,108 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.request; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.hubo.gillajabi.crawl.domain.constant.PrecipitationForm; +import com.hubo.gillajabi.crawl.domain.constant.SkyCondition; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiWeatherCurrentResponse; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +@Setter +@Slf4j +public class WeatherCurrentDto { + + private Float liveTemperature; + + // 최저 기온 + private Float lowTemperature; + + // 최고 기온 + private Float highTemperature; + + // 날씨 + private SkyCondition skyCondition; + + // 기상 특보 TODO: 수정 (예 : 폭염 경보) + private String weatherAlert; + + // 습도 reh % 0~100 + private Integer humidity; + + // 강수형태 + private PrecipitationForm precipitationForm; + + // 강수확률 + private Integer precipitationProbability; + + // 강수량 mm + private Float precipitationAmount; + + // 적설량 + private Float snowfallAmount; + + // 풍속 m/s + private Float windSpeed; + + public void updateWeatherDtoFromCurrent( ApiWeatherCurrentResponse.Current current) { + try { + switch (current.getCategory()) { + case "POP": + this.setPrecipitationProbability(parseSafeInt(current.getFcstValue())); + break; + case "PTY": + this.setPrecipitationForm(PrecipitationForm.fromCode(parseSafeInt(current.getFcstValue()))); + break; + case "PCP": + this.setPrecipitationAmount(parseSafeFloat(current.getFcstValue(), "강수없음")); + break; + case "REH": + this.setHumidity(parseSafeInt(current.getFcstValue())); + break; + case "SNO": + this.setSnowfallAmount(parseSafeFloat(current.getFcstValue(), "적설없음")); + break; + case "SKY": + this.setSkyCondition(SkyCondition.fromCode(parseSafeInt(current.getFcstValue()))); + break; + case "TMP": + this.setLiveTemperature(Float.parseFloat(current.getFcstValue())); + break; + case "TMN": + this.setLowTemperature(Float.parseFloat(current.getFcstValue())); + break; + case "TMX": + this.setHighTemperature(Float.parseFloat(current.getFcstValue())); + break; + case "WSD": + this.setWindSpeed(Float.parseFloat(current.getFcstValue())); + break; + default: // 처리할 카테고리가 아닐 경우 + break; + } + } catch (NumberFormatException e) { + log.info("날씨 데이터 파싱 중 오류 발생: " + e.getMessage()); + } + } + + private float parseSafeFloat(String value, String defaultValue) { + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue.equals("강수없음") || defaultValue.equals("적설없음") ? 0.0f : Float.parseFloat(defaultValue); + } + } + + private int parseSafeInt(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return 0; + } + } + +} + + diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java new file mode 100644 index 00000000..4adb6be6 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java @@ -0,0 +1,47 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.request; + +import com.hubo.gillajabi.crawl.domain.constant.MediumTermSkyCondition; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiWeatherMediumTermResponse; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class WeatherTermDTO { + + private int lowTemperature3; + private int highTemperature3; + private MediumTermSkyCondition skyCondition3; + private int lowTemperature4; + private int highTemperature4; + private MediumTermSkyCondition skyCondition4; + private int lowTemperature5; + private int highTemperature5; + private MediumTermSkyCondition skyCondition5; + private int lowTemperature6; + private int highTemperature6; + private MediumTermSkyCondition skyCondition6; + private int lowTemperature7; + private int highTemperature7; + private MediumTermSkyCondition skyCondition7; + + public static WeatherTermDTO of(ApiWeatherMediumTermResponse.Temperature temperature, ApiWeatherMediumTermResponse.Detail detail){ + WeatherTermDTO dto = new WeatherTermDTO(); + dto.setLowTemperature3(temperature.getTaMin3()); + dto.setHighTemperature3(temperature.getTaMax3()); + dto.setSkyCondition3(MediumTermSkyCondition.fromString(detail.getWf3Am())); + dto.setLowTemperature4(temperature.getTaMin4()); + dto.setHighTemperature4(temperature.getTaMax4()); + dto.setSkyCondition4(MediumTermSkyCondition.fromString(detail.getWf4Am())); + dto.setLowTemperature5(temperature.getTaMin5()); + dto.setHighTemperature5(temperature.getTaMax5()); + dto.setSkyCondition5(MediumTermSkyCondition.fromString(detail.getWf5Am())); + dto.setLowTemperature6(temperature.getTaMin6()); + dto.setHighTemperature6(temperature.getTaMax6()); + dto.setSkyCondition6(MediumTermSkyCondition.fromString(detail.getWf6Am())); + dto.setLowTemperature7(temperature.getTaMin7()); + dto.setHighTemperature7(temperature.getTaMax7()); + dto.setSkyCondition7(MediumTermSkyCondition.fromString(detail.getWf7Am())); + return dto; + } +} From 06f07e4bf7db565c15fe4ee60b23acced0edd7c1 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 01:40:26 +0900 Subject: [PATCH 22/31] =?UTF-8?q?feat:=20MediumTermSkyCondition=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gillajabi/crawl/domain/constant/MediumTermSkyCondition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java index ed1749ec..3959cec4 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyCondition.java @@ -30,7 +30,7 @@ public String getDescription() { public static MediumTermSkyCondition fromString(String value){ return switch (value) { - case "맑음" -> CLEAR; + case "맑음", "" -> CLEAR; case "구름많음" -> MOSTLY_CLOUDY; case "구름많고 비" -> MOSTLY_CLOUDY_WITH_RAIN; case "구름많고 눈" -> MOSTLY_CLOUDY_WITH_SNOW; From e59f4bcf19b3ef6168f304275b9f990e438260fa Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:36:52 +0900 Subject: [PATCH 23/31] =?UTF-8?q?refactor:=20=EB=8B=AC=EB=9D=BC=EC=A7=84?= =?UTF-8?q?=20DTO=20=EC=9D=B4=EB=A6=84=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RoadCrawlFacadeService.java | 12 ++--- .../busan/RoadCrawlBusanServiceImpl.java | 4 +- .../service/duru/RoadCityDuruService.java | 20 ++++---- .../duru/RoadCourseDetailDuruService.java | 16 +++---- ...andler.java => RoadCourseDuruHandler.java} | 4 +- .../service/duru/RoadCourseDuruService.java | 12 ++--- .../duru/RoadCourseDuruThemeService.java | 7 +-- .../service/duru/RoadGpxInfoDuruService.java | 6 +-- .../service/RoadCrawlFacadeServiceTest.java | 27 +++++------ .../service/duru/RoadCityDuruServiceTest.java | 3 +- .../duru/RoadCourseDetailDuruServiceTest.java | 29 ++++++------ .../duru/RoadCourseDuruHandlerTest.java} | 12 ++--- .../duru/RoadCourseDuruServiceTest.java | 23 +++++---- .../duru/RoadCourseThemeDuruServiceTest.java | 47 +++++++++++++++++++ 14 files changed, 132 insertions(+), 90 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{RoadDuruCourseHandler.java => RoadCourseDuruHandler.java} (93%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/application/service/RoadCrawlFacadeServiceTest.java (76%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/service/duru/RoadCityDuruServiceTest.java (93%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/service/duru/RoadCourseDetailDuruServiceTest.java (81%) rename src/test/java/com/hubo/gillajabi/{road/application/service/RoadDuruCourseHandlerTest.java => crawl/domain/service/duru/RoadCourseDuruHandlerTest.java} (92%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/service/duru/RoadCourseDuruServiceTest.java (83%) create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseThemeDuruServiceTest.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java index 38a4e3c0..361c79e9 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeService.java @@ -5,8 +5,8 @@ import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import com.hubo.gillajabi.crawl.domain.service.busan.RoadBusanThemeHandler; import com.hubo.gillajabi.crawl.domain.service.busan.RoadCrawlBusanCourseHandler; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadThemeDuruHandler; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -15,21 +15,21 @@ @RequiredArgsConstructor public class RoadCrawlFacadeService { - private final RoadDuruCourseHandler roadDuruCourseHandler; + private final RoadCourseDuruHandler roadCourseDuruHandler; private final RoadCrawlBusanCourseHandler roadCrawlBusanCourseHandler; - private final RoadDuruThemeHandler roadDuruThemeHandler; + private final RoadThemeDuruHandler roadThemeDuruHandler; private final RoadBusanThemeHandler roadBusanThemeHandler; public RoadCrawlResponse.CourseResult getCourse(final CityCrawlName cityCrawlName) { return switch (cityCrawlName) { - case DURU -> roadDuruCourseHandler.handle(); + case DURU -> roadCourseDuruHandler.handle(); case BUSAN -> roadCrawlBusanCourseHandler.handle(); }; } public RoadCrawlResponse.ThemeResult getTheme(final CityCrawlName cityCrawlName) { return switch (cityCrawlName) { - case DURU -> roadDuruThemeHandler.handle(); + case DURU -> roadThemeDuruHandler.handle(); case BUSAN -> roadBusanThemeHandler.handle(); }; } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java index 607c60a4..585cc926 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/busan/RoadCrawlBusanServiceImpl.java @@ -2,7 +2,7 @@ ; import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; import com.hubo.gillajabi.global.common.dto.ApiProperties; -import com.hubo.gillajabi.crawl.domain.constant.CityName; +import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -20,7 +20,7 @@ public class RoadCrawlBusanServiceImpl { @PostConstruct private void init() { - this.busanApiProperties = roadEndpointConfig.getEndpoint(CityName.BUSAN); + this.busanApiProperties = roadEndpointConfig.getEndpoint(CityCrawlName.BUSAN); if (this.busanApiProperties == null) { throw new IllegalStateException("BUSAN Crawl Strategy 가 초기화 되지 않았습니다."); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java index cdd3612b..7dad21ad 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruService.java @@ -3,7 +3,7 @@ import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.util.helper.RoadCrawlResponseParserHelper; @@ -33,29 +33,29 @@ public List saveCity(final List responseItems) { private void processCourseItem(final List cities, final ApiCourseResponse.Course item) { try { - final CityRequestDTO cityRequestDTO = createCityRequestDTOFromCourseItem(item); - final City city = createOrFindCity(cityRequestDTO); + final CityRequest cityRequest = createCityRequestDTOFromCourseItem(item); + final City city = createOrFindCity(cityRequest); cities.add(city); } catch (final CrawlException e) { log.error("CityService.saveCity 실행중 문제 발생: " + e.getMessage()); } } - private CityRequestDTO createCityRequestDTOFromCourseItem(final ApiCourseResponse.Course item) { + private CityRequest createCityRequestDTOFromCourseItem(final ApiCourseResponse.Course item) { final String provinceName = RoadCrawlResponseParserHelper.parseDuruResponseByProvince(item.getSigun()); final Province province = Province.fromValue(provinceName); final String cityName = RoadCrawlResponseParserHelper.parseDuruResponseByCity(item.getSigun()); - return CityRequestDTO.of(cityName, province); + return CityRequest.of(cityName, province); } - private City createOrFindCity(final CityRequestDTO cityRequestDTO) { - return cityRepository.findByNameAndProvince(cityRequestDTO.getName(), cityRequestDTO.getProvince()) - .orElseGet(() -> createAndSaveCity(cityRequestDTO)); + private City createOrFindCity(final CityRequest cityRequest) { + return cityRepository.findByNameAndProvince(cityRequest.getName(), cityRequest.getProvince()) + .orElseGet(() -> createAndSaveCity(cityRequest)); } - private City createAndSaveCity(final CityRequestDTO cityRequestDTO) { - final City city = City.createCity(cityRequestDTO); + private City createAndSaveCity(final CityRequest cityRequest) { + final City city = City.createCity(cityRequest); cityRepository.save(city); return city; } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java index 68e4824e..f7bee437 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruService.java @@ -2,7 +2,7 @@ import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseDetailRepository; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; @@ -31,22 +31,22 @@ public List saveDuruCourseDetail(final List courseDetails = new ArrayList<>(); responseItems.forEach(item -> { final Course course = findCourseByName(courses, item.getCrsKorNm()); - final CourseDetailRequestDTO courseDetailRequestDTO = buildCourseDetailRequest(item); + final CourseDetailRequest courseDetailRequest = buildCourseDetailRequest(item); - final CourseDetail courseDetail = createOrUpdateDetail(courseDetailRequestDTO, course); + final CourseDetail courseDetail = createOrUpdateDetail(courseDetailRequest, course); updateCourseDetailByCourse(course, courseDetail); courseDetails.add(courseDetail); }); return courseDetails; } - private CourseDetailRequestDTO buildCourseDetailRequest(final ApiCourseResponse.Course item) { + private CourseDetailRequest buildCourseDetailRequest(final ApiCourseResponse.Course item) { final String startPoint = extractPoint(item.getTravelerinfo(), startPattern, 1); final String endPoint = extractPoint(item.getTravelerinfo(), endPattern, 1); final String startPointTransport = extractPoint(item.getTravelerinfo(), startPattern, 2); final String endPointTransport = extractPoint(item.getTravelerinfo(), endPattern, 2); - return CourseDetailRequestDTO.of(item, startPoint, endPoint, startPointTransport, endPointTransport); + return CourseDetailRequest.of(item, startPoint, endPoint, startPointTransport, endPointTransport); } private String extractPoint(final String info, final Pattern pattern, final int group) { @@ -54,12 +54,12 @@ private String extractPoint(final String info, final Pattern pattern, final int return matcher.find() ? matcher.group(group) : null; } - private CourseDetail createOrUpdateDetail(final CourseDetailRequestDTO request, final Course course) { + private CourseDetail createOrUpdateDetail(final CourseDetailRequest request, final Course course) { final CourseDetail existingDetail = course.getCourseDetail(); return existingDetail != null ? updateExistingDetail(existingDetail, request) : createNewCourseDetail(request, course); } - private CourseDetail updateExistingDetail(final CourseDetail detail, final CourseDetailRequestDTO request) { + private CourseDetail updateExistingDetail(final CourseDetail detail, final CourseDetailRequest request) { if (detail.isCheckUpdate(request)) { detail.update(request); return courseDetailRepository.save(detail); @@ -67,7 +67,7 @@ private CourseDetail updateExistingDetail(final CourseDetail detail, final Cours return detail; } - private CourseDetail createNewCourseDetail(final CourseDetailRequestDTO request, final Course course) { + private CourseDetail createNewCourseDetail(final CourseDetailRequest request, final Course course) { final CourseDetail newDetail = CourseDetail.createCourseDetail(request); course.addCourseDetail(newDetail); return courseDetailRepository.save(newDetail); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java similarity index 93% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java index 1bbe4144..4fc992fa 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruCourseHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java @@ -13,9 +13,9 @@ @Service @RequiredArgsConstructor -public class RoadDuruCourseHandler { +public class RoadCourseDuruHandler { - private final RoadCrawlDuruServiceImpl duruCrawlService; + private final RoadDuruCrawlDuruServiceImpl duruCrawlService; private final RoadCityDuruService cityService; private final RoadCourseDuruService roadCourseDuruService; private final RoadCourseDetailDuruService roadCourseDetailDuruService; diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruService.java index 35f5445c..55341477 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruService.java @@ -4,7 +4,7 @@ import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; @@ -34,10 +34,10 @@ public List saveDuruCourse(final List response private Course processCourseItem(ApiCourseResponse.Course item, List cities) { City city = findCity(item, cities); CourseTheme courseTheme = findCourseTheme(item); - CourseRequestDTO courseRequestDTO = CourseRequestDTO.of(item, city, courseTheme); + CourseRequest courseRequest = CourseRequest.of(item, city, courseTheme); Optional existingCourse = courseRepository.findByOriginName(item.getCrsKorNm()); - return createOrUpdateCourse(courseRequestDTO, existingCourse); + return createOrUpdateCourse(courseRequest, existingCourse); } private City findCity(final ApiCourseResponse.Course item, final List cities) { @@ -57,13 +57,13 @@ private CourseTheme findCourseTheme(final ApiCourseResponse.Course item) { .orElseThrow(() -> new IllegalArgumentException("CourseTheme 정보가 없습니다.")); } - private Course createOrUpdateCourse(final CourseRequestDTO request, final Optional existingCourse) { + private Course createOrUpdateCourse(final CourseRequest request, final Optional existingCourse) { return existingCourse .map(course -> updateExistingCourse(request, course)) .orElseGet(() -> createAndSaveNewCourse(request)); } - private Course updateExistingCourse(final CourseRequestDTO request, final Course existingCourse) { + private Course updateExistingCourse(final CourseRequest request, final Course existingCourse) { if (existingCourse.checkUpdate(request)) { existingCourse.update(request); courseRepository.save(existingCourse); @@ -71,7 +71,7 @@ private Course updateExistingCourse(final CourseRequestDTO request, final Course return existingCourse; } - private Course createAndSaveNewCourse(final CourseRequestDTO request) { + private Course createAndSaveNewCourse(final CourseRequest request) { Course newCourse = Course.createCourse(request); courseRepository.save(newCourse); return newCourse; diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java index ddac4225..97451f49 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruThemeService.java @@ -1,7 +1,7 @@ package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; import lombok.RequiredArgsConstructor; @@ -41,12 +41,13 @@ private CourseTheme findOrCreateCourseTheme(ApiThemeResponse.Theme item) { } private CourseTheme updateExistingCourseTheme(CourseTheme existingTheme, ApiThemeResponse.Theme item) { - existingTheme.update(item.getThemedescs(), item.getLinemsg()); + CourseThemeRequest requestDTO = CourseThemeRequest.from(item); + existingTheme.update(requestDTO); return existingTheme; } private CourseTheme createNewCourseTheme(ApiThemeResponse.Theme item) { - CourseThemeRequestDTO requestDTO = CourseThemeRequestDTO.from(item); + CourseThemeRequest requestDTO = CourseThemeRequest.from(item); return CourseTheme.createCourseTheme(requestDTO); } } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java index 4fc82adb..cc0462c3 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruService.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; -import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; +import com.hubo.gillajabi.crawl.domain.service.PrimaryCrawlingService; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiDuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; @@ -26,7 +26,7 @@ public class RoadGpxInfoDuruService { private final GpxInfoRepository gpxInfoRepository; - private final ResponseCrawlService responseCrawlService; + private final PrimaryCrawlingService primaryCrawlingService; private static final XmlMapper xmlMapper = new XmlMapper(); private static final ObjectMapper jsonMapper = new ObjectMapper(); @@ -63,7 +63,7 @@ private boolean shouldSkip(String path) { private ApiDuruGpxResponse fetchGpxResponse(String gpxUrl) throws IOException { URI uri = URI.create(gpxUrl); - String response = responseCrawlService.fetchApiResponse(uri); + String response = primaryCrawlingService.fetchApiResponse(uri); return xmlMapper.readValue(response, ApiDuruGpxResponse.class); } diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeServiceTest.java similarity index 76% rename from src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeServiceTest.java index c92d22c0..e7cdbd92 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadCrawlFacadeServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/application/service/RoadCrawlFacadeServiceTest.java @@ -1,15 +1,14 @@ -package com.hubo.gillajabi.road.application.service; +package com.hubo.gillajabi.crawl.application.service; import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; -import com.hubo.gillajabi.crawl.application.service.*; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import com.hubo.gillajabi.crawl.domain.service.busan.RoadBusanThemeHandler; import com.hubo.gillajabi.crawl.domain.service.busan.RoadCrawlBusanCourseHandler; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruHandler; +import com.hubo.gillajabi.crawl.domain.service.duru.RoadThemeDuruHandler; import com.navercorp.fixturemonkey.FixtureMonkey; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,13 +21,13 @@ public class RoadCrawlFacadeServiceTest { @Mock - private RoadDuruCourseHandler roadDuruCourseHandler; + private RoadCourseDuruHandler roadCourseDuruHandler; @Mock private RoadCrawlBusanCourseHandler roadCrawlBusanCourseHandler; @Mock - private RoadDuruThemeHandler roadDuruThemeHandler; + private RoadThemeDuruHandler roadThemeDuruHandler; @Mock private RoadBusanThemeHandler roadBusanThemeHandler; @@ -45,14 +44,14 @@ public void testGetDuruCourse() { RoadCrawlResponse.CourseResult duruCourseResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.CourseResult.class) .sample(); - when(roadDuruCourseHandler.handle()).thenReturn(duruCourseResult); + when(roadCourseDuruHandler.handle()).thenReturn(duruCourseResult); // when assertEquals(duruCourseResult, roadCrawlFacadeService.getCourse(CityCrawlName.DURU)); // then - verify(roadDuruCourseHandler).handle(); - verifyNoMoreInteractions(roadDuruThemeHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); + verify(roadCourseDuruHandler).handle(); + verifyNoMoreInteractions(roadThemeDuruHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); } @Test @@ -69,7 +68,7 @@ public void testGetBusanCourse() { // then verify(roadCrawlBusanCourseHandler).handle(); - verifyNoMoreInteractions(roadDuruCourseHandler, roadDuruThemeHandler, roadBusanThemeHandler); + verifyNoMoreInteractions(roadCourseDuruHandler, roadThemeDuruHandler, roadBusanThemeHandler); } @Test @@ -79,14 +78,14 @@ public void testGetDuruTheme() { RoadCrawlResponse.ThemeResult duruThemeResult = fixtureMonkey.giveMeBuilder(RoadCrawlResponse.ThemeResult.class) .sample(); - when(roadDuruThemeHandler.handle()).thenReturn(duruThemeResult); + when(roadThemeDuruHandler.handle()).thenReturn(duruThemeResult); // when assertEquals(duruThemeResult, roadCrawlFacadeService.getTheme(CityCrawlName.DURU)); // then - verify(roadDuruThemeHandler).handle(); - verifyNoMoreInteractions(roadDuruCourseHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); + verify(roadThemeDuruHandler).handle(); + verifyNoMoreInteractions(roadCourseDuruHandler, roadCrawlBusanCourseHandler, roadBusanThemeHandler); } @Test @@ -103,6 +102,6 @@ public void testGetBusanTheme() { // then verify(roadBusanThemeHandler).handle(); - verifyNoMoreInteractions(roadDuruCourseHandler, roadDuruThemeHandler, roadCrawlBusanCourseHandler); + verifyNoMoreInteractions(roadCourseDuruHandler, roadThemeDuruHandler, roadCrawlBusanCourseHandler); } } diff --git a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruServiceTest.java similarity index 93% rename from src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruServiceTest.java index ff786a3e..9136c371 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCityDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCityDuruServiceTest.java @@ -1,8 +1,7 @@ -package com.hubo.gillajabi.road.domain.service.duru; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.City; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCityDuruService; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; import com.navercorp.fixturemonkey.FixtureMonkey; diff --git a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruServiceTest.java similarity index 81% rename from src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruServiceTest.java index be893b65..8f726c14 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDetailDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDetailDuruServiceTest.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.road.domain.service.duru; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; @@ -6,10 +6,9 @@ import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDetailDuruService; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseDetailRepository; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; @@ -56,24 +55,24 @@ public ApiCourseResponse.Course giveMeDuruCourseResponse(){ } - public CityRequestDTO giveMeCityRequestDTO(){ - CityRequestDTO cityRequestDTO = fixtureMonkey.giveMeBuilder(CityRequestDTO.class).sample(); - cityRequestDTO.setProvince(Province.BUSAN); - return cityRequestDTO; + public CityRequest giveMeCityRequestDTO(){ + CityRequest cityRequest = fixtureMonkey.giveMeBuilder(CityRequest.class).sample(); + cityRequest.setProvince(Province.BUSAN); + return cityRequest; } - public CourseThemeRequestDTO giveMeCourseThemeRequestDTO(){ - CourseThemeRequestDTO courseThemeRequestDTO = fixtureMonkey.giveMeBuilder(CourseThemeRequestDTO.class).sample(); - courseThemeRequestDTO.setName("남파랑길"); - return courseThemeRequestDTO; + public CourseThemeRequest giveMeCourseThemeRequestDTO(){ + CourseThemeRequest courseThemeRequest = fixtureMonkey.giveMeBuilder(CourseThemeRequest.class).sample(); + courseThemeRequest.setName("남파랑길"); + return courseThemeRequest; } - public CourseRequestDTO giveMeCourseRequestDTO() { + public CourseRequest giveMeCourseRequestDTO() { ApiCourseResponse.Course response = giveMeDuruCourseResponse(); City city = City.createCity(giveMeCityRequestDTO()); CourseTheme courseTheme = CourseTheme.createCourseTheme(giveMeCourseThemeRequestDTO()); - return CourseRequestDTO.of(response, city, courseTheme); + return CourseRequest.of(response, city, courseTheme); } @DisplayName("DuruCourseResponse.Course를 받아서 새로운 CourseDetail객체를 생성하고 저장") diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java similarity index 92% rename from src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java index b31e781e..08691c64 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruCourseHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java @@ -1,11 +1,9 @@ -package com.hubo.gillajabi.road.application.service; +package com.hubo.gillajabi.crawl.domain.service.duru; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruCourseHandler; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.*; -import com.hubo.gillajabi.crawl.domain.service.duru.*; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; @@ -26,10 +24,10 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class RoadDuruCourseHandlerTest { +class RoadCourseDuruHandlerTest { @Mock - private RoadCrawlDuruServiceImpl duruCrawlService; + private RoadDuruCrawlDuruServiceImpl duruCrawlService; @Mock private RoadCityDuruService cityService; @@ -44,7 +42,7 @@ class RoadDuruCourseHandlerTest { private RoadGpxInfoDuruService roadGpxInfoDuruService; @InjectMocks - private RoadDuruCourseHandler roadDuruCourseHandler; + private RoadCourseDuruHandler roadCourseDuruHandler; private static final FixtureMonkey fixtureMonkey = FixtureMonkey.builder().build(); @@ -105,7 +103,7 @@ void testHandle() { mockDuruHandle(); // when - RoadCrawlResponse.CourseResult result = roadDuruCourseHandler.handle(); + RoadCrawlResponse.CourseResult result = roadCourseDuruHandler.handle(); // then assertEquals(1, result.getCityCount()); diff --git a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruServiceTest.java similarity index 83% rename from src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruServiceTest.java index 7254337d..c11f75f2 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadCourseDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruServiceTest.java @@ -1,13 +1,12 @@ -package com.hubo.gillajabi.road.domain.service.duru; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.Province; import com.hubo.gillajabi.crawl.domain.entity.City; import com.hubo.gillajabi.crawl.domain.entity.Course; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruService; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequestDTO; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseRepository; import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; @@ -43,11 +42,11 @@ class RoadCourseDuruServiceTest { public City createCity() { - CityRequestDTO cityRequestDTO = fixtureMonkey.giveMeBuilder(CityRequestDTO.class).sample(); - cityRequestDTO.setProvince(Province.GYEONGNAM); - cityRequestDTO.setName("김해시"); + CityRequest cityRequest = fixtureMonkey.giveMeBuilder(CityRequest.class).sample(); + cityRequest.setProvince(Province.GYEONGNAM); + cityRequest.setName("김해시"); - return City.createCity(cityRequestDTO); + return City.createCity(cityRequest); } public ApiCourseResponse.Course createDuruCourseResponseCourse() { @@ -77,12 +76,12 @@ public void saveDuruCourse() { ApiCourseResponse.Course response = createDuruCourseResponseCourse(); responseItems.add(response); - CourseThemeRequestDTO courseThemeRequestDTO = fixtureMonkey.giveMeBuilder(CourseThemeRequestDTO.class).sample(); - CourseTheme courseTheme = CourseTheme.createCourseTheme(courseThemeRequestDTO); + CourseThemeRequest courseThemeRequest = fixtureMonkey.giveMeBuilder(CourseThemeRequest.class).sample(); + CourseTheme courseTheme = CourseTheme.createCourseTheme(courseThemeRequest); when(courseRepository.findByOriginName(any())).thenReturn(Optional.empty()); when(courseThemeRepository.findByName(any())).thenReturn(Optional.of(courseTheme)); - when(courseRepository.save(any())).thenReturn(Course.createCourse(CourseRequestDTO.of(response, city, courseTheme))); + when(courseRepository.save(any())).thenReturn(Course.createCourse(CourseRequest.of(response, city, courseTheme))); // when List courses = roadCourseDuruService.saveDuruCourse(responseItems, cities); diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseThemeDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseThemeDuruServiceTest.java new file mode 100644 index 00000000..def3cb26 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseThemeDuruServiceTest.java @@ -0,0 +1,47 @@ +package com.hubo.gillajabi.crawl.domain.service.duru; + + +import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; +import com.hubo.gillajabi.crawl.infrastructure.persistence.CourseThemeRepository; +import com.navercorp.fixturemonkey.FixtureMonkey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MockitoExtension.class) +class RoadCourseThemeDuruServiceTest { + + @Mock + private CourseThemeRepository courseThemeRepository; + + @InjectMocks + private RoadCourseDuruThemeService roadCourseDuruThemeService; + + private final FixtureMonkey fixtureMonkey = FixtureMonkey.create(); + + @Test + @DisplayName("테마를 저장한다") + public void 테마를_저장한다() { + // given + List items = new ArrayList<>(); + items.add(fixtureMonkey.giveMeOne(ApiThemeResponse.Theme.class)); + + // when + List courseThemes = roadCourseDuruThemeService.saveDuruTheme(items); + + // then + assertEquals(1, courseThemes.size()); + + } + + +} From 3fa327eb924f2a6fc26bd2387691484f2c959bfd Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:38:40 +0900 Subject: [PATCH 24/31] =?UTF-8?q?refactor:=20api=EB=A5=BC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=EA=B3=BC=20api?= =?UTF-8?q?=ED=98=B8=EC=B6=9C,=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...e.java => InternalApiResponseService.java} | 2 +- ...va => InternalApiResponseServiceImpl.java} | 5 +- .../service/PrimaryCrawlingService.java | 90 +++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/{ResponseCrawlService.java => InternalApiResponseService.java} (87%) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/{ResponseCrawlServiceImpl.java => InternalApiResponseServiceImpl.java} (93%) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingService.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseService.java similarity index 87% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseService.java index df9a8798..9018a710 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseService.java @@ -5,7 +5,7 @@ import java.net.URI; import java.util.Optional; -public interface ResponseCrawlService { +interface InternalApiResponseService { OptionalfindByRequestUrl(String string); String fetchApiResponse(URI uri); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceImpl.java similarity index 93% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceImpl.java index 0219cc80..748b3b8b 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/ResponseCrawlServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceImpl.java @@ -15,18 +15,19 @@ @Transactional @RequiredArgsConstructor @Slf4j -public class ResponseCrawlServiceImpl implements ResponseCrawlService { +class InternalApiResponseServiceImpl implements InternalApiResponseService { private final CrawlApiResponseRepository crawlApiResponseRepository; private final RestTemplate restTemplate; - @Transactional(readOnly = true) @Override + @Transactional(readOnly = true) public Optional findByRequestUrl(String string) { return crawlApiResponseRepository.findByRequestUrl(string); } @Override + @Transactional(noRollbackFor = RuntimeException.class) public String fetchApiResponse(final URI uri) { String url = uri.toString(); Optional cachedResponse = getCachedResponse(url); diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingService.java new file mode 100644 index 00000000..8ead58f3 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingService.java @@ -0,0 +1,90 @@ +package com.hubo.gillajabi.crawl.domain.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractApiResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; +import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.net.URI; + + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class PrimaryCrawlingService { + + private final InternalApiResponseService responseCrawlService; + private final ObjectMapper objectMapper; + + @FunctionalInterface + public interface CrawlPageFunction { + AbstractApiResponse crawlPage(int pageNo) throws Exception; + } + + public List crawlItems(final CrawlPageFunction crawlPageFunction) { + int pageNo = 1; + List allItems = new ArrayList<>(); + while (true) { + try { + AbstractApiResponse response = crawlPageFunction.crawlPage(pageNo); + List items = extractItems(response); // 데이터 추출 + if (isLastPage(items)) { + return allItems; + } + allItems.addAll(items); + pageNo++; + } catch (Exception e) { + throw new CrawlException(500, "공공데이터 호출 중 예기치 못한 오류 발생 :" + e.getMessage()); + } + } + } + + public T crawlPage(Class responseType, URI uri) { + try { + final String response = responseCrawlService.fetchApiResponse(uri); + objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true); + return objectMapper.readValue(response, responseType); + } catch (JsonProcessingException e) { + throw new CrawlException(500, "JSON 처리 중 오류 발생: " + e.getMessage()); + } + } + + public AbstractApiResponse crawlOnePage(Class itemType, URI uri) { + try { + final String response = responseCrawlService.fetchApiResponse(uri); + JavaType responseType = objectMapper.getTypeFactory().constructParametricType(AbstractApiResponse.class, itemType); + + return objectMapper.readValue(response, responseType); + } catch (JsonProcessingException e) { + throw new CrawlException(500, "JSON 처리 중 오류 발생: " + e.getMessage()); + } + } + + private boolean isLastPage(List items) { + return items == null || items.isEmpty(); + } + + public List extractItems(AbstractApiResponse response) { + if (response != null && response.getResponse() != null && response.getResponse().getBody() != null && response.getResponse().getBody().getItems() != null) { + return response.getResponse().getBody().getItems().getItem(); + } + return new ArrayList<>(); + } + + public String fetchApiResponse(URI uri) { + try { + return responseCrawlService.fetchApiResponse(uri); + } catch (Exception e) { + throw new CrawlException(500, "API 호출 중 예기치 못한 오류 발생: " + e.getMessage()); + } + } + + +} \ No newline at end of file From 4120adb8c8957b6538f40f149915202fc912aa69 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:39:21 +0900 Subject: [PATCH 25/31] =?UTF-8?q?refactor:=20=EB=88=84=EB=9D=BD=EB=90=9C?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/common/service/CrawlService.java | 12 ++++ .../common/service/CrawlServiceImpl.java | 57 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/main/java/com/hubo/gillajabi/global/common/service/CrawlService.java create mode 100644 src/main/java/com/hubo/gillajabi/global/common/service/CrawlServiceImpl.java diff --git a/src/main/java/com/hubo/gillajabi/global/common/service/CrawlService.java b/src/main/java/com/hubo/gillajabi/global/common/service/CrawlService.java new file mode 100644 index 00000000..643ca459 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/global/common/service/CrawlService.java @@ -0,0 +1,12 @@ +package com.hubo.gillajabi.global.common.service; + +import com.hubo.gillajabi.crawl.domain.entity.CrawlApiResponse; + +import java.net.URI; +import java.util.Optional; + +public interface CrawlService { + Optional findByRequestUrl(String string); + + String fetchApiResponse(URI uri); +} diff --git a/src/main/java/com/hubo/gillajabi/global/common/service/CrawlServiceImpl.java b/src/main/java/com/hubo/gillajabi/global/common/service/CrawlServiceImpl.java new file mode 100644 index 00000000..f6809e83 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/global/common/service/CrawlServiceImpl.java @@ -0,0 +1,57 @@ +package com.hubo.gillajabi.global.common.service; + +import com.hubo.gillajabi.crawl.domain.entity.CrawlApiResponse; +import com.hubo.gillajabi.crawl.infrastructure.persistence.CrawlApiResponseRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Slf4j +@Transactional +public class CrawlServiceImpl implements CrawlService{ + private final CrawlApiResponseRepository crawlApiResponseRepository; + private final RestTemplate restTemplate; + + @Transactional(readOnly = true) + @Override + public Optional findByRequestUrl(String url) { + return crawlApiResponseRepository.findByRequestUrl(url); + } + + @Override + public String fetchApiResponse(URI uri) { + String url = uri.toString(); + Optional cachedResponse = getCachedResponse(url); + return cachedResponse.orElseGet(() -> fetchFromApiAndCache(url, uri)); + } + + private Optional getCachedResponse(String url) { + return findByRequestUrl(url).map(CrawlApiResponse::getResponse); + } + + private String fetchFromApiAndCache(String url, URI uri) { + try { + String response = restTemplate.getForObject(uri, String.class); + log.info("API 응답을 가져왔습니다. url: {}", url); + saveApiResponse(url, response); + return response; + } catch (Exception e) { + throw new RuntimeException("API 응답을 가져오는 중 문제가 발생했습니다.", e); + } + } + + private void saveApiResponse(String apiUrl, String response) { + CrawlApiResponse crawlApiResponse = CrawlApiResponse.builder() + .requestUrl(apiUrl) + .response(response) + .build(); + crawlApiResponseRepository.save(crawlApiResponse); + } +} From f8e608167acfdb43b02d20489eeaedc1d57252a0 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:41:34 +0900 Subject: [PATCH 26/31] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80=20-=20Abstr?= =?UTF-8?q?actApiResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/dto/response/AbstractApiResponse.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java index 1bb65f6d..a958a485 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/AbstractApiResponse.java @@ -7,6 +7,11 @@ import java.util.List; +/** + * API 응답의 공통 구조를 정의한 추상 클래스 + * "공공 데이터 포털"에서 가져오는 api의 응답 구조를 정의한 추상 클래스 + * @param + */ @Getter @Setter public class AbstractApiResponse implements ValidatableResponse{ From a80e8abcfa6af1acc47992792f5ee678a5b8f2ba Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:42:11 +0900 Subject: [PATCH 27/31] =?UTF-8?q?feat:=20=EC=9D=BC=EA=B8=B0=20=EC=98=88?= =?UTF-8?q?=EB=B3=B4=203~7=EC=9D=BC=20=EA=B4=80=EB=A0=A8=20ResponseDTO=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApiWeatherMediumTermResponse.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java index 8cab2067..4c963ab0 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherMediumTermResponse.java @@ -1,6 +1,5 @@ package com.hubo.gillajabi.crawl.infrastructure.dto.response; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Getter; import lombok.Setter; @@ -8,8 +7,7 @@ public class ApiWeatherMediumTermResponse { @Getter @Setter - @JsonIgnoreProperties(ignoreUnknown = true) - public static class MediumTerm { + public static class Temperature { private String regId; private int taMin3; private int taMin3Low; @@ -43,4 +41,32 @@ public static class MediumTerm { private int taMax7High; } + @Getter + @Setter + public static class Detail { + private String regId; + // 강수 확률 + private int rnSt3Am; + private int rnSt3Pm; + private int rnSt4Am; + private int rnSt4Pm; + private int rnSt5Am; + private int rnSt5Pm; + private int rnSt6Am; + private int rnSt6Pm; + private int rnSt7Am; + private int rnSt7Pm; + // 하늘 상태 + private String wf3Am; + private String wf3Pm; + private String wf4Am; + private String wf4Pm; + private String wf5Am; + private String wf5Pm; + private String wf6Am; + private String wf6Pm; + private String wf7Am; + private String wf7Pm; + } + } From 8ec3353dc46d13f25b6dd27e95b7e09f7a0c4d8c Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 02:44:02 +0900 Subject: [PATCH 28/31] =?UTF-8?q?feat:=20=EB=82=A0=EC=94=A8=20=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=EB=A7=81=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presenation/WeatherCrawlController.java | 46 ++++++ .../service/WeatherCrawlServiceImpl.java | 136 ++++++++++++++---- .../dto/request/WeatherTermDTO.java | 2 +- .../dto/response/ApiWeatherAlertResponse.java | 16 +++ 4 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/hubo/gillajabi/crawl/application/presenation/WeatherCrawlController.java create mode 100644 src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherAlertResponse.java diff --git a/src/main/java/com/hubo/gillajabi/crawl/application/presenation/WeatherCrawlController.java b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/WeatherCrawlController.java new file mode 100644 index 00000000..84565365 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/application/presenation/WeatherCrawlController.java @@ -0,0 +1,46 @@ +package com.hubo.gillajabi.crawl.application.presenation; + +import com.hubo.gillajabi.crawl.domain.service.WeatherCrawlService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/weather/crawl") +@RequiredArgsConstructor +@Tag(name = "Weather crawl 컨트롤러 ", description = "관리자 공공 데이터 포털 호출 api(날씨 관련)") +public class WeatherCrawlController { + + private final WeatherCrawlService weatherCrawlService; + + @Operation(summary = "전국 날씨 크롤링 (당일) ", description = "전국 날씨를 3일치를 들고 옵니다.") + @PostMapping("/current") + public ResponseEntity startWeatherCurrentCrawl() { + + weatherCrawlService.currentCrawl(); + + return ResponseEntity.ok().build(); + } + + @Operation(summary = "전국 날씨 크롤링 (일주일) ", description = "3일 이후 부터 ~7일까지의 날씨 정보를 크롤링합니다.") + @PostMapping("/medium-term") + public ResponseEntity startWeatherMediumTermCrawl() { + + weatherCrawlService.weatherMediumTermCrawl(); + + return ResponseEntity.ok().build(); + } + + @Operation(summary = "전국 기상 특보 크롤링 (지금 현재) ", description = "미구현") + @PostMapping("/weather_alert") + public ResponseEntity startWeatherAlertCrawl() { + + weatherCrawlService.alertCrawl(); + + return ResponseEntity.status(500).body("미구현"); + } + +} + diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java index 5df6333f..4ed34ab6 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImpl.java @@ -4,8 +4,11 @@ import com.hubo.gillajabi.crawl.domain.constant.ForecastType; import com.hubo.gillajabi.crawl.domain.constant.WeatherRedisConstants; import com.hubo.gillajabi.crawl.domain.entity.City; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.WeatherDto; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.WeatherCurrentDto; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.WeatherTermDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractApiResponse; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiWeatherCurrentResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiWeatherMediumTermResponse; import com.hubo.gillajabi.crawl.infrastructure.exception.CrawlException; import com.hubo.gillajabi.crawl.infrastructure.persistence.CityRepository; import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; @@ -20,6 +23,7 @@ import java.net.URI; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.*; @@ -33,7 +37,7 @@ public class WeatherCrawlServiceImpl implements WeatherCrawlService { private final WeatherEndpointConfig weatherEndpointConfig; private final CrawlApiBuilderHelper crawlApiBuilderHelper; - private final GenericCrawlerService genericCrawlerService; + private final PrimaryCrawlingService primaryCrawlingService; private final CityRepository cityRepository; private final StringRedisTemplate stringRedisTemplate; @@ -51,56 +55,136 @@ private void validateWeatherApiProperties() { } } + @Override public void currentCrawl() { List cities = cityRepository.findAll(); cities.forEach(city -> { - LocalDate date = LocalDate.now(); try { - List currentWeatherData = crawlWeatherData(city); - processWeatherData(city, date, currentWeatherData); + List currentWeatherData = crawlWeatherData(city, LocalDate.now()); + processWeatherData(city, currentWeatherData); } catch (Exception e) { log.info("날씨 데이터 수집 중 오류 발생: " + e.getMessage()); } }); } - private List crawlWeatherData(City city) { - LocalDate targetDate = LocalDate.now(); - - GenericCrawlerService.CrawlPageFunction function = pageNo -> { + private List crawlWeatherData(City city, LocalDate targetDate) { + return primaryCrawlingService.crawlItems(pageNo -> { URI uri = crawlApiBuilderHelper.buildUri(weatherApiProperties.get(ForecastType.CURRENT), city.getNx(), city.getNy(), targetDate, pageNo); - return genericCrawlerService.crawlPage(ApiWeatherCurrentResponse.class, uri); - }; - - return genericCrawlerService.crawlItems(function); + return primaryCrawlingService.crawlPage(ApiWeatherCurrentResponse.class, uri); + }); } - private void processWeatherData(City city, LocalDate date, List currentWeatherData) { - Map weatherDataByTime = new HashMap<>(); + private void processWeatherData(City city, List currentWeatherData) { + Map weatherDataByTime = new HashMap<>(); + Map dailyWeatherData = new HashMap<>(); + for (ApiWeatherCurrentResponse.Current current : currentWeatherData) { - WeatherDto weatherDto = weatherDataByTime.computeIfAbsent(current.getFcstTime(), k -> new WeatherDto()); - weatherDto.updateWeatherDtoFromCurrent(current); + String dateTimeKey = current.getFcstDate() + current.getFcstTime(); + WeatherCurrentDto weatherCurrentDto = weatherDataByTime.computeIfAbsent(dateTimeKey, k -> new WeatherCurrentDto()); + weatherCurrentDto.updateWeatherDtoFromCurrent(current); + + WeatherCurrentDto dailyWeatherCurrentDto = dailyWeatherData.computeIfAbsent(current.getFcstDate(), k -> new WeatherCurrentDto()); + + updateTemperatureData(current, dailyWeatherCurrentDto); + } + + saveWeatherDataToRedis(city, weatherDataByTime, dailyWeatherData); + } + + /** + * 현재 날씨 데이터에서 최저/최고 기온 데이터를 추출하여 WeatherCurrentDto에 저장 + * 최저기온 : 오전 6시, 최고기온 : 오후 3시 + * @param current : response + * @param dailyWeatherCurrentDto : 날짜별 날씨 데이터 + */ + private void updateTemperatureData(ApiWeatherCurrentResponse.Current current, WeatherCurrentDto dailyWeatherCurrentDto) { + if ("TMN".equals(current.getCategory()) && "0600".equals(current.getFcstTime())) { + dailyWeatherCurrentDto.setLowTemperature(Float.parseFloat(current.getFcstValue())); + } + if ("TMX".equals(current.getCategory()) && "1500".equals(current.getFcstTime())) { + dailyWeatherCurrentDto.setHighTemperature(Float.parseFloat(current.getFcstValue())); } + } + + private void saveWeatherDataToRedis(City city, Map weatherDataByTime, Map dailyWeatherData) { + weatherDataByTime.forEach((dateTimeKey, weatherCurrentDto) -> { + saveWeatherData(city, dateTimeKey, weatherCurrentDto); + }); - weatherDataByTime.forEach((baseTime, weatherDto) -> { + dailyWeatherData.forEach((fcstDate, dailyWeatherCurrentDto) -> { + saveDailyWeatherData(city, fcstDate, dailyWeatherCurrentDto); + }); + } + + private void saveWeatherData(City city, String dateTimeKey, WeatherCurrentDto weatherCurrentDto) { + try { + String date = dateTimeKey.substring(0, 8); + String time = dateTimeKey.substring(8); + LocalDate parsedDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyyMMdd")); + String key = WeatherRedisConstants.makeWeatherKey(city, parsedDate, time); + String value = objectMapper.writeValueAsString(weatherCurrentDto); + stringRedisTemplate.opsForValue().set(key, value); + } catch (Exception e) { + throw new CrawlException(4, "날씨 데이터 저장 오류: " + e.getMessage()); + } + } + + private void saveDailyWeatherData(City city, String fcstDate, WeatherCurrentDto dailyWeatherCurrentDto) { + try { + LocalDate parsedDate = LocalDate.parse(fcstDate, DateTimeFormatter.ofPattern("yyyyMMdd")); + String dailyKey = WeatherRedisConstants.makeWeatherKey(city, parsedDate, null); + String dailyValue = objectMapper.writeValueAsString(dailyWeatherCurrentDto); + stringRedisTemplate.opsForValue().set(dailyKey, dailyValue); + } catch (Exception e) { + throw new CrawlException(4, "날씨 데이터 저장 오류: " + e.getMessage()); + } + } + + @Override + public void weatherMediumTermCrawl() { + List cities = cityRepository.findAll(); + cities.forEach(city -> { + LocalDate date = LocalDate.now(); try { - String key = WeatherRedisConstants.makeWeatherKey(city, date, baseTime); - String value = objectMapper.writeValueAsString(weatherDto); - stringRedisTemplate.opsForValue().set(key, value); + ApiWeatherMediumTermResponse.Detail mediumTermWeatherDetailData = crawlMediumTermWeatherDetailData(date, city); + ApiWeatherMediumTermResponse.Temperature mediumTermWeatherTemperatureData = crawlMediumTermWeatherTemperatureData(date, city); + + processMediumTermWeatherData(city, date, mediumTermWeatherDetailData, mediumTermWeatherTemperatureData); } catch (Exception e) { - throw new CrawlException(2, "날씨 데이터 저장 오류: " + e.getMessage()); + log.info("중기 날씨 데이터 수집 중 오류 발생: " + e.getMessage()); } }); } - @Override - public void weatherMediumTermCrawl() { - System.out.println("Weather Medium Term Crawl"); + private ApiWeatherMediumTermResponse.Temperature crawlMediumTermWeatherTemperatureData(LocalDate date, City city) { + URI weatherTemperatureURI = crawlApiBuilderHelper.buildUri("getMidTa", weatherApiProperties.get(ForecastType.MEDIUM_TERM), city, 1, date); + AbstractApiResponse response = primaryCrawlingService.crawlOnePage(ApiWeatherMediumTermResponse.Temperature.class, weatherTemperatureURI); + return response.getResponse().getBody().getItems().getItem().get(0); + } + + private ApiWeatherMediumTermResponse.Detail crawlMediumTermWeatherDetailData(LocalDate date, City city) { + URI weatherDetailURI = crawlApiBuilderHelper.buildUri("getMidLandFcst", weatherApiProperties.get(ForecastType.MEDIUM_TERM), city, 1, date); + AbstractApiResponse response = primaryCrawlingService.crawlOnePage(ApiWeatherMediumTermResponse.Detail.class, weatherDetailURI); + return response.getResponse().getBody().getItems().getItem().get(0); + } + + private void processMediumTermWeatherData(City city, LocalDate date, ApiWeatherMediumTermResponse.Detail mediumTermWeatherDetailData, ApiWeatherMediumTermResponse.Temperature mediumTermWeatherTemperatureData) { + final LocalDate makeKeyDate = date.plusDays(3); + final WeatherTermDTO weatherTermDTO = WeatherTermDTO.of(mediumTermWeatherDetailData, mediumTermWeatherTemperatureData); + try { + String key = WeatherRedisConstants.makeWeatherKey(city, makeKeyDate, null); + String value = objectMapper.writeValueAsString(weatherTermDTO); + stringRedisTemplate.opsForValue().set(key, value); + + } catch (Exception e) { + throw new CrawlException(4, "중기 날씨 데이터 저장 오류: " + e.getMessage()); + } } @Override public void alertCrawl() { - System.out.println("Weather Alert Crawl"); + //TODO: 예보 구현 필요 } } diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java index 4adb6be6..728350df 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/WeatherTermDTO.java @@ -25,7 +25,7 @@ public class WeatherTermDTO { private int highTemperature7; private MediumTermSkyCondition skyCondition7; - public static WeatherTermDTO of(ApiWeatherMediumTermResponse.Temperature temperature, ApiWeatherMediumTermResponse.Detail detail){ + public static WeatherTermDTO of(ApiWeatherMediumTermResponse.Detail detail, ApiWeatherMediumTermResponse.Temperature temperature) { WeatherTermDTO dto = new WeatherTermDTO(); dto.setLowTemperature3(temperature.getTaMin3()); dto.setHighTemperature3(temperature.getTaMax3()); diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherAlertResponse.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherAlertResponse.java new file mode 100644 index 00000000..9b6e06e1 --- /dev/null +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/response/ApiWeatherAlertResponse.java @@ -0,0 +1,16 @@ +package com.hubo.gillajabi.crawl.infrastructure.dto.response; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Getter; +import lombok.Setter; + +public class ApiWeatherAlertResponse extends AbstractApiResponse { + + + @Getter + @Setter + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Alert { + //TODO : 예보 시스템 + } +} From d2b2374bf491377fcbdeae4d2d33a6327d2d3c25 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 03:52:03 +0900 Subject: [PATCH 29/31] =?UTF-8?q?refactor:=20RoadDuruAbstractCrawlDuruServ?= =?UTF-8?q?ice=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20public=20=EC=A0=91=EA=B7=BC=20=EC=A0=9C=EC=96=B4?= =?UTF-8?q?=EC=9E=90=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...wlDuruService.java => RoadDuruAbstractCrawlDuruService.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{RoadAbstractCrawlDuruService.java => RoadDuruAbstractCrawlDuruService.java} (75%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruAbstractCrawlDuruService.java similarity index 75% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruAbstractCrawlDuruService.java index c908b33f..b78d0019 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadAbstractCrawlDuruService.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruAbstractCrawlDuruService.java @@ -2,7 +2,7 @@ import java.util.List; -public abstract class RoadAbstractCrawlDuruService { +abstract class RoadDuruAbstractCrawlDuruService { public abstract List crawlCourse(); public abstract List crawlTheme(); From 87645259ac2ec0343a6f433409dc50e33f1519a0 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Fri, 28 Jun 2024 03:53:00 +0900 Subject: [PATCH 30/31] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawl/domain/service/duru/RoadCourseDuruHandler.java | 2 +- .../{road => crawl}/domain/constant/ProvinceTest.java | 3 +-- .../domain/service/duru/RoadCourseDuruHandlerTest.java | 2 +- .../domain/service/duru/RoadGpxInfoDuruServiceTest.java | 7 +++---- 4 files changed, 6 insertions(+), 8 deletions(-) rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/constant/ProvinceTest.java (96%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/service/duru/RoadGpxInfoDuruServiceTest.java (93%) diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java index 4fc992fa..169b78f7 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandler.java @@ -15,7 +15,7 @@ @RequiredArgsConstructor public class RoadCourseDuruHandler { - private final RoadDuruCrawlDuruServiceImpl duruCrawlService; + private final RoadCrawlDuruServiceImpl duruCrawlService; private final RoadCityDuruService cityService; private final RoadCourseDuruService roadCourseDuruService; private final RoadCourseDetailDuruService roadCourseDetailDuruService; diff --git a/src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java similarity index 96% rename from src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java index 1a831f0a..0057186f 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/constant/ProvinceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/ProvinceTest.java @@ -1,6 +1,5 @@ -package com.hubo.gillajabi.road.domain.constant; +package com.hubo.gillajabi.crawl.domain.constant; -import com.hubo.gillajabi.crawl.domain.constant.Province; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java index 08691c64..e658f9f2 100644 --- a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCourseDuruHandlerTest.java @@ -27,7 +27,7 @@ class RoadCourseDuruHandlerTest { @Mock - private RoadDuruCrawlDuruServiceImpl duruCrawlService; + private RoadCrawlDuruServiceImpl duruCrawlService; @Mock private RoadCityDuruService cityService; diff --git a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruServiceTest.java similarity index 93% rename from src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruServiceTest.java index 2b6c125c..8ee2b5df 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/service/duru/RoadGpxInfoDuruServiceTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadGpxInfoDuruServiceTest.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.road.domain.service.duru; +package com.hubo.gillajabi.crawl.domain.service.duru; import com.fasterxml.jackson.core.JsonProcessingException; @@ -6,8 +6,7 @@ import com.hubo.gillajabi.crawl.domain.entity.CourseDetail; import com.hubo.gillajabi.crawl.domain.entity.GpxInfo; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadGpxInfoDuruService; -import com.hubo.gillajabi.crawl.domain.service.ResponseCrawlService; +import com.hubo.gillajabi.crawl.domain.service.PrimaryCrawlingService; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseDetailRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiDuruGpxResponse; import com.hubo.gillajabi.crawl.infrastructure.persistence.GpxInfoRepository; @@ -36,7 +35,7 @@ class RoadGpxInfoDuruServiceTest { private GpxInfoRepository gpxInfoRepository; @Mock - private ResponseCrawlService responseCrawlService; + private PrimaryCrawlingService responseCrawlService; @InjectMocks private RoadGpxInfoDuruService roadGpxInfoDuruService; From 2891448f59fc38ee664b82ee5c853443f13423f7 Mon Sep 17 00:00:00 2001 From: gimdonghyeon Date: Sat, 29 Jun 2024 11:51:31 +0900 Subject: [PATCH 31/31] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=B2=98=EB=A6=AC=20-=20=EC=B6=94=ED=9B=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EB=8F=84=EB=A1=9D=20=ED=95=98?= =?UTF-8?q?=EA=B2=A0=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE-hubo-gillajabi-resources | 2 +- .../crawl/domain/entity/CourseSection.java | 1 - .../crawl/domain/entity/CourseTheme.java | 16 ++- .../duru/RoadCrawlDuruServiceImpl.java | 16 +-- ...Handler.java => RoadThemeDuruHandler.java} | 4 +- .../dto/request/CourseRequest.java | 4 + .../domain/constant/CourseLevelTest.java | 33 +++++ .../domain/constant/CycleTypeTest.java | 3 +- .../constant/MediumTermSkyConditionTest.java | 88 ++++++++++++ .../constant/PrecipitationFormTest.java | 40 ++++++ .../domain/constant/SkyConditionTest.java | 43 ++++++ .../constant/WeatherRedisConstantsTest.java | 63 +++++++++ .../crawl/domain/entity/CityTest.java | 26 ++++ .../crawl/domain/entity/CourseTest.java | 54 ++++++++ .../InternalApiResponseServiceTest.java | 97 ++++++++++++++ .../service/PrimaryCrawlingServiceTest.java | 7 + .../service/WeatherCrawlServiceImplTest.java | 4 + .../duru/RoadCrawlDuruServiceTest.java | 91 +++++++++++++ .../duru/RoadThemeDuruHandlerTest.java} | 11 +- .../config/RoadEndpointConfigTest.java | 2 +- .../config/WeatherEndpointConfigTest.java | 54 ++++++++ .../infraStructure/dto/CourseReqeustTest.java | 77 +++++++++++ .../helper/CrawlApiBuilderHelperTest.java | 125 ++++++++++++++++++ ...RoadRoadCrawlResponseParserHelperTest.java | 55 ++++++++ 24 files changed, 886 insertions(+), 30 deletions(-) rename src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/{RoadDuruThemeHandler.java => RoadThemeDuruHandler.java} (81%) create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java rename src/test/java/com/hubo/gillajabi/{road => crawl}/domain/constant/CycleTypeTest.java (92%) create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyConditionTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationFormTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/SkyConditionTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstantsTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/entity/CityTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/entity/CourseTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingServiceTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImplTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceTest.java rename src/test/java/com/hubo/gillajabi/{road/application/service/RoadDuruThemeHandlerTest.java => crawl/domain/service/duru/RoadThemeDuruHandlerTest.java} (81%) rename src/test/java/com/hubo/gillajabi/{road => crawl}/infraStructure/config/RoadEndpointConfigTest.java (96%) create mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/WeatherEndpointConfigTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/dto/CourseReqeustTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java create mode 100644 src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/RoadRoadCrawlResponseParserHelperTest.java diff --git a/BE-hubo-gillajabi-resources b/BE-hubo-gillajabi-resources index 5ea7ac9f..de8c9997 160000 --- a/BE-hubo-gillajabi-resources +++ b/BE-hubo-gillajabi-resources @@ -1 +1 @@ -Subproject commit 5ea7ac9f2a5cf3d4338f04a881980bacd72307a1 +Subproject commit de8c99978ddeb685984300e05310da3a78ed62f2 diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseSection.java b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseSection.java index b1825c1c..0498f9af 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseSection.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseSection.java @@ -3,7 +3,6 @@ import com.hubo.gillajabi.crawl.domain.constant.CourseLevel; import com.hubo.gillajabi.global.BaseEntity; import jakarta.persistence.*; -import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseTheme.java b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseTheme.java index 36c6eb98..5c8b00b5 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseTheme.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/entity/CourseTheme.java @@ -1,10 +1,12 @@ package com.hubo.gillajabi.crawl.domain.entity; -import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequestDTO; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.global.BaseEntity; import jakarta.persistence.*; import lombok.*; +import java.util.Objects; + @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -24,16 +26,16 @@ public class CourseTheme extends BaseEntity { @Column(columnDefinition = "TEXT") private String description; - public static CourseTheme createCourseTheme(CourseThemeRequestDTO requestDTO) { + public static CourseTheme createCourseTheme(CourseThemeRequest requestDTO) { return new CourseTheme(null, requestDTO.getName(), requestDTO.getShortDescription(), requestDTO.getDescription()); } - public void update(String themedescs, String linemsg) { - if (!themedescs.equals(this.description)) { - this.name = themedescs; + public void update(CourseThemeRequest requestDTO) { + if(!Objects.equals(this.getShortDescription(), requestDTO.getShortDescription())) { + this.shortDescription = requestDTO.getShortDescription(); } - if (!linemsg.equals(this.shortDescription)) { - this.shortDescription = linemsg; + if(!Objects.equals(this.description, requestDTO.getDescription())) { + this.description = requestDTO.getDescription(); } } } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java index 0dd777fe..c06e2f73 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceImpl.java @@ -1,7 +1,7 @@ package com.hubo.gillajabi.crawl.domain.service.duru; import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; -import com.hubo.gillajabi.crawl.domain.service.GenericCrawlerService; +import com.hubo.gillajabi.crawl.domain.service.PrimaryCrawlingService; import com.hubo.gillajabi.crawl.infrastructure.dto.response.AbstractApiResponse; import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; @@ -19,15 +19,15 @@ @Service @RequiredArgsConstructor @Slf4j -public class RoadCrawlDuruServiceImpl extends RoadAbstractCrawlDuruService { +public class RoadCrawlDuruServiceImpl extends RoadDuruAbstractCrawlDuruService { private final RoadEndpointConfig roadEndpointConfig; private final CrawlApiBuilderHelper crawlApiBuilderHelper; - private final GenericCrawlerService genericCrawlerService; + private final PrimaryCrawlingService primaryCrawlingService; private static ApiProperties duruApiProperties; @PostConstruct - private void init() { + protected void init() { duruApiProperties = roadEndpointConfig.getEndpoint(CityCrawlName.DURU); validateDuruApiProperties(); } @@ -40,22 +40,22 @@ private void validateDuruApiProperties() { @Override public List crawlCourse() { - return genericCrawlerService.crawlItems(this::crawlCoursePage); + return primaryCrawlingService.crawlItems(this::crawlCoursePage); } @Override public List crawlTheme() { - return genericCrawlerService.crawlItems(this::crawlThemePage); + return primaryCrawlingService.crawlItems(this::crawlThemePage); } private AbstractApiResponse crawlCoursePage(int pageNo) throws Exception { URI uri = crawlApiBuilderHelper.buildUri("courseList", duruApiProperties, pageNo); - return genericCrawlerService.crawlPage(ApiCourseResponse.class, uri); + return primaryCrawlingService.crawlPage(ApiCourseResponse.class, uri); } private AbstractApiResponse crawlThemePage(int pageNo) throws Exception { URI uri = crawlApiBuilderHelper.buildUri("routeList", duruApiProperties, pageNo); - return genericCrawlerService.crawlPage(ApiThemeResponse.class, uri); + return primaryCrawlingService.crawlPage(ApiThemeResponse.class, uri); } diff --git a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandler.java similarity index 81% rename from src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java rename to src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandler.java index 12620f59..4e66a16a 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadDuruThemeHandler.java +++ b/src/main/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandler.java @@ -3,8 +3,6 @@ import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruThemeService; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCrawlDuruServiceImpl; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -13,7 +11,7 @@ @Service @RequiredArgsConstructor -public class RoadDuruThemeHandler { +public class RoadThemeDuruHandler { private final RoadCrawlDuruServiceImpl duruCrawlService; private final RoadCourseDuruThemeService roadCourseDuruThemeService; diff --git a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java index 1681530a..5f699bde 100644 --- a/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java +++ b/src/main/java/com/hubo/gillajabi/crawl/infrastructure/dto/request/CourseRequest.java @@ -38,6 +38,10 @@ public static CourseRequest of(ApiCourseResponse.Course item, City city, CourseT } private static String parseCourseNumber(final String courseName) { + if (courseName == null || courseName.split(" ").length < 2) { + throw new IllegalArgumentException("잘못된 코스 이름 : " + courseName); + } return courseName.split(" ")[1].replace("코스", ""); } + } diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java new file mode 100644 index 00000000..7b2acc0a --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CourseLevelTest.java @@ -0,0 +1,33 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class CourseLevelTest { + + @Test + @DisplayName("레벨 1은 LOW 반환") + void 두루누비_level_1일_경우() { + assertEquals(CourseLevel.LOW, CourseLevel.fromValue("1")); + } + + @Test + @DisplayName("레벨 2은 MIDDLE 반환") + void 두루누비_level_2일_경우() { + assertEquals(CourseLevel.MIDDLE, CourseLevel.fromValue("2")); + } + + @Test + @DisplayName("레벨 3은 HIGH 반환") + void 두루누비_level_3일_경우() { + assertEquals(CourseLevel.HIGH, CourseLevel.fromValue("3")); + } + + @Test + @DisplayName("잘못된 레벨 값 예외 발생") + void 두루누비_level이_잘못된_값일_경우() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> CourseLevel.fromValue("4")); + assertEquals("잘못된 레벨 값 : 4", exception.getMessage()); + } +} diff --git a/src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java similarity index 92% rename from src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java index d9a6e795..abeeb98d 100644 --- a/src/test/java/com/hubo/gillajabi/road/domain/constant/CycleTypeTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/CycleTypeTest.java @@ -1,6 +1,5 @@ -package com.hubo.gillajabi.road.domain.constant; +package com.hubo.gillajabi.crawl.domain.constant; -import com.hubo.gillajabi.crawl.domain.constant.CycleType; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyConditionTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyConditionTest.java new file mode 100644 index 00000000..3569ac90 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/MediumTermSkyConditionTest.java @@ -0,0 +1,88 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class MediumTermSkyConditionTest { + + @Test + @DisplayName("맑음은 CLEAR 반환") + void 맑음은_CLEAR반환() { + assertEquals(MediumTermSkyCondition.CLEAR, MediumTermSkyCondition.fromString("맑음")); + } + + @Test + @DisplayName("빈 문자열은 CLEAR 반환") + void 빈문자열은_CLEAR반환() { + assertEquals(MediumTermSkyCondition.CLEAR, MediumTermSkyCondition.fromString("")); + } + + @Test + @DisplayName("구름많음은 MOSTLY_CLOUDY 반환") + void 구름많음은_MOSTLY_CLOUDY반환() { + assertEquals(MediumTermSkyCondition.MOSTLY_CLOUDY, MediumTermSkyCondition.fromString("구름많음")); + } + + @Test + @DisplayName("구름많고 비는 MOSTLY_CLOUDY_WITH_RAIN 반환") + void 구름많고_비는_MOSTLY_CLOUDY_WITH_RAIN반환() { + assertEquals(MediumTermSkyCondition.MOSTLY_CLOUDY_WITH_RAIN, MediumTermSkyCondition.fromString("구름많고 비")); + } + + @Test + @DisplayName("구름많고 눈은 MOSTLY_CLOUDY_WITH_SNOW 반환") + void 구름많고_눈은_MOSTLY_CLOUDY_WITH_SNOW반환() { + assertEquals(MediumTermSkyCondition.MOSTLY_CLOUDY_WITH_SNOW, MediumTermSkyCondition.fromString("구름많고 눈")); + } + + @Test + @DisplayName("구름많고 비/눈은 MOSTLY_CLOUDY_WITH_RAIN_AND_SNOW 반환") + void 구름많고_비눈은_MOSTLY_CLOUDY_WITH_RAIN_AND_SNOW반환() { + assertEquals(MediumTermSkyCondition.MOSTLY_CLOUDY_WITH_RAIN_AND_SNOW, MediumTermSkyCondition.fromString("구름많고 비/눈")); + } + + @Test + @DisplayName("구름많고 소나기는 MOSTLY_CLOUDY_WITH_SHOWERS 반환") + void 구름많고_소나기는_MOSTLY_CLOUDY_WITH_SHOWERS반환() { + assertEquals(MediumTermSkyCondition.MOSTLY_CLOUDY_WITH_SHOWERS, MediumTermSkyCondition.fromString("구름많고 소나기")); + } + + @Test + @DisplayName("흐림은 CLOUDY 반환") + void 흐림은_CLOUDY반환() { + assertEquals(MediumTermSkyCondition.CLOUDY, MediumTermSkyCondition.fromString("흐림")); + } + + @Test + @DisplayName("흐리고 비는 CLOUDY_WITH_RAIN 반환") + void 흐리고_비는_CLOUDY_WITH_RAIN반환() { + assertEquals(MediumTermSkyCondition.CLOUDY_WITH_RAIN, MediumTermSkyCondition.fromString("흐리고 비")); + } + + @Test + @DisplayName("흐리고 눈은 CLOUDY_WITH_SNOW 반환") + void 흐리고_눈은_CLOUDY_WITH_SNOW반환() { + assertEquals(MediumTermSkyCondition.CLOUDY_WITH_SNOW, MediumTermSkyCondition.fromString("흐리고 눈")); + } + + @Test + @DisplayName("흐리고 비/눈은 CLOUDY_WITH_RAIN_AND_SNOW 반환") + void 흐리고_비눈은_CLOUDY_WITH_RAIN_AND_SNOW반환() { + assertEquals(MediumTermSkyCondition.CLOUDY_WITH_RAIN_AND_SNOW, MediumTermSkyCondition.fromString("흐리고 비/눈")); + } + + @Test + @DisplayName("흐리고 소나기는 CLOUDY_WITH_SHOWERS 반환") + void 흐리고_소나기는_CLOUDY_WITH_SHOWERS반환() { + assertEquals(MediumTermSkyCondition.CLOUDY_WITH_SHOWERS, MediumTermSkyCondition.fromString("흐리고 소나기")); + } + + @Test + @DisplayName("잘못된 값 예외 발생") + void 잘못된값_예외발생() { + assertThrows(IllegalArgumentException.class, () -> MediumTermSkyCondition.fromString("잘못된 값")); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationFormTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationFormTest.java new file mode 100644 index 00000000..6cf4dc29 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/PrecipitationFormTest.java @@ -0,0 +1,40 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class PrecipitationFormTest { + + @Test + @DisplayName("강수형태 코드가 0일 경우 없음을 반환") + void 강수형태_코드가_0일_경우_없음을_반환(){ + assertEquals(PrecipitationForm.NONE, PrecipitationForm.fromCode(0)); + } + + @Test + @DisplayName("강수형태 코드가 1일 경우 비를 반환") + void 강수형태_코드가_1일_경우_비를_반환(){ + assertEquals(PrecipitationForm.RAIN, PrecipitationForm.fromCode(1)); + } + + @Test + @DisplayName("강수형태 코드가 2일 경우 비/눈을 반환") + void 강수형태_코드가_2일_경우_비눈을_반환(){ + assertEquals(PrecipitationForm.RAIN_AND_SNOW, PrecipitationForm.fromCode(2)); + } + + @Test + @DisplayName("강수형태 코드가 3일 경우 눈을 반환") + void 강수형태_코드가_3일_경우_눈을_반환(){ + assertEquals(PrecipitationForm.SNOW, PrecipitationForm.fromCode(3)); + } + + @Test + @DisplayName("강수형태 코드가 4일 경우 소나기를 반환") + void 강수형태_코드가_4일_경우_소나기를_반환(){ + assertEquals(PrecipitationForm.SHOWER, PrecipitationForm.fromCode(4)); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/SkyConditionTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/SkyConditionTest.java new file mode 100644 index 00000000..36e403ee --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/SkyConditionTest.java @@ -0,0 +1,43 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class SkyConditionTest { + + @Test + @DisplayName("하늘상태 코드 1은 CLEAR 반환") + void 하늘상태_코드_1일_경우() { + assertEquals(SkyCondition.CLEAR, SkyCondition.fromCode(1)); + } + + @Test + @DisplayName("하늘상태 코드 2은 PARTLY_CLOUDY 반환") + void 하늘상태_코드_2일_경우() { + assertEquals(SkyCondition.PARTLY_CLOUDY, SkyCondition.fromCode(2)); + } + + @Test + @DisplayName("하늘상태 코드 3은 MOSTLY_CLOUDY 반환") + void 하늘상태_코드_3일_경우() { + assertEquals(SkyCondition.MOSTLY_CLOUDY, SkyCondition.fromCode(3)); + } + + @Test + @DisplayName("하늘상태 코드 4은 CLOUDY 반환") + void 하늘상태_코드_4일_경우() { + assertEquals(SkyCondition.CLOUDY, SkyCondition.fromCode(4)); + } + + @Test + @DisplayName("잘못된 하늘상태 코드 예외 발생") + void 잘못된_하늘상태_코드일_경우() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> SkyCondition.fromCode(5)); + assertEquals("잘못된 하늘 상태 코드 : 5", exception.getMessage()); + } + + +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstantsTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstantsTest.java new file mode 100644 index 00000000..8bb7579e --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/constant/WeatherRedisConstantsTest.java @@ -0,0 +1,63 @@ +package com.hubo.gillajabi.crawl.domain.constant; + +import com.hubo.gillajabi.crawl.domain.entity.City; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +class WeatherRedisConstantsTest { + + private City createCity(){ + CityRequest cityRequest = new CityRequest("Seoul", Province.SEOUL, "서울특별시"); + return City.createCity(cityRequest); + } + + @Test + @DisplayName("기본 키 생성") + public void 기본_키_생성() { + City city = createCity(); + LocalDate date = LocalDate.of(2023, 6, 28); + String result = WeatherRedisConstants.makeWeatherKey(city, date, null); + assertThat(result).isEqualTo("weather:Seoul:20230628"); + } + + @Test + @DisplayName("기본 키 생성 (기본 시간 포함)") + public void 기본_키_생성_기본_시간_포함() { + City city = createCity(); + LocalDate date = LocalDate.of(2023, 6, 28); + String result = WeatherRedisConstants.makeWeatherKey(city, date, "1200"); + assertThat(result).isEqualTo("weather:Seoul:20230628:1200"); + } + + @Test + @DisplayName("기본 키 생성 (도시 이름 테스트)") + public void 기본_키_생성_도시_이름_테스트() { + City city = createCity(); + LocalDate date = LocalDate.of(2023, 6, 28); + String result = WeatherRedisConstants.makeWeatherKey(city, date, null); + assertThat(result).isEqualTo("weather:Seoul:20230628"); + } + + @Test + @DisplayName("기본 키 생성 (날짜 테스트)") + public void 기본_키_생성_날짜_테스트() { + City city = createCity(); + LocalDate date = LocalDate.of(2023, 12, 31); + String result = WeatherRedisConstants.makeWeatherKey(city, date, null); + assertThat(result).isEqualTo("weather:Seoul:20231231"); + } + + @Test + @DisplayName("기본 키 생성 (시간 테스트)") + public void 기본_키_생성_시간_테스트() { + City city = createCity(); + LocalDate date = LocalDate.of(2023, 6, 28); + String result = WeatherRedisConstants.makeWeatherKey(city, date, "0600"); + assertThat(result).isEqualTo("weather:Seoul:20230628:0600"); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CityTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CityTest.java new file mode 100644 index 00000000..72f4da4c --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CityTest.java @@ -0,0 +1,26 @@ +package com.hubo.gillajabi.crawl.domain.entity; + +import com.hubo.gillajabi.crawl.domain.constant.Province; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class CityTest { + + @Test + @DisplayName("createCity 메서드는 CityRequest를 사용하여 City 객체를 생성한다") + public void createCity_유효한_CityRequest로_City_객체_생성() { + // given + CityRequest cityRequest = CityRequest.of("Seoul", Province.SEOUL, "서울"); + + // when + City city = City.createCity(cityRequest); + + // then + assertEquals("Seoul", city.getName()); + assertEquals(Province.SEOUL, city.getProvince()); + assertEquals("서울", city.getDescription()); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CourseTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CourseTest.java new file mode 100644 index 00000000..3be80ca8 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/entity/CourseTest.java @@ -0,0 +1,54 @@ +package com.hubo.gillajabi.crawl.domain.entity; + +import com.hubo.gillajabi.crawl.domain.constant.Province; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; +import com.navercorp.fixturemonkey.FixtureMonkey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CourseTest { + + public static FixtureMonkey fixtureMonkey = FixtureMonkey.builder().build(); + + private ApiCourseResponse.Course createApiResponse() { + return fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class) + .set("sigun", "경남 김해시") + .set("crsKorNm", "남파랑길 1코스") + .set("crsLevel", "1") + .set("crsDstnc", "5") + .set("crsTotlRqrmHour", "2") + .sample(); + } + + private City createCity() { + CityRequest cityRequest = CityRequest.of("김해시", Province.GYEONGNAM, "김해"); + return City.createCity(cityRequest); + } + + private static CourseTheme createCourseTheme() { + CourseThemeRequest courseThemeRequest = fixtureMonkey.giveMeOne(CourseThemeRequest.class); + return CourseTheme.createCourseTheme(courseThemeRequest); + } + + + @Test + @DisplayName("createCourse 메서드는 CourseReqeust를 사용한다") + public void createCourse_유효한_CourseRequest로_Course_객체_생성() { + // given + CourseRequest courseRequest = CourseRequest.of(createApiResponse(), createCity(), createCourseTheme()); + + // when + Course course = Course.createCourse(courseRequest); + + // then + assertEquals("남파랑길 1코스", course.getOriginName()); + assertEquals(5, course.getDistance()); + } + +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceTest.java new file mode 100644 index 00000000..51b3fb9a --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/InternalApiResponseServiceTest.java @@ -0,0 +1,97 @@ +package com.hubo.gillajabi.crawl.domain.service; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.web.client.RestTemplate; + +import com.hubo.gillajabi.crawl.domain.entity.CrawlApiResponse; +import com.hubo.gillajabi.crawl.infrastructure.persistence.CrawlApiResponseRepository; + +@ExtendWith(MockitoExtension.class) +class InternalApiResponseServiceTest { + + @Mock + private CrawlApiResponseRepository crawlApiResponseRepository; + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private InternalApiResponseServiceImpl roadCrawlApiResponseServiceImpl; + + @Test + @DisplayName("URI를 호출하여 API 응답을 가져온다") + public void uri를_호출에_성공한다() throws Exception { + // Given + String apiUrl = "http://test.com"; + String response = "response"; + URI uri = new URI(apiUrl); + + when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.empty()); + when(restTemplate.getForObject(uri, String.class)).thenReturn(response); + + // When + String result = roadCrawlApiResponseServiceImpl.fetchApiResponse(uri); + + // Then + assertEquals(response, result); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CrawlApiResponse.class); + verify(crawlApiResponseRepository, times(1)).save(captor.capture()); + CrawlApiResponse captured = captor.getValue(); + + assertEquals(apiUrl, captured.getRequestUrl()); + assertEquals(response, captured.getResponse()); + } + + @Test + @DisplayName("캐시된 응답이 있을 경우, 캐시된 응답을 반환한다") + public void 캐시된_응답이_있을_경우_캐시된_응답을_반환_성공() throws Exception { + // Given + String apiUrl = "http://test.com"; + String cachedResponse = "cached response"; + URI uri = new URI(apiUrl); + + when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.of( + CrawlApiResponse.builder().requestUrl(apiUrl).response(cachedResponse).build() + )); + + // When + String result = roadCrawlApiResponseServiceImpl.fetchApiResponse(uri); + + // Then + assertEquals(cachedResponse, result); + verify(crawlApiResponseRepository, never()).save(any(CrawlApiResponse.class)); + } + + @Test + @DisplayName("잘못된 uri일 경우 에러가 발생한다") + public void 잘못된_uri일_경우_에러가_발생한다() throws Exception { + // Given + String apiUrl = "http://test.com"; + URI uri = new URI(apiUrl); + + when(crawlApiResponseRepository.findByRequestUrl(apiUrl)).thenReturn(Optional.empty()); + when(restTemplate.getForObject(uri, String.class)).thenThrow(new RuntimeException()); + + // When / Then + RuntimeException exception = assertThrows(RuntimeException.class, () -> { + roadCrawlApiResponseServiceImpl.fetchApiResponse(uri); + }); + + assertEquals("API 응답을 가져오는 중 문제가 발생했습니다.", exception.getMessage()); + verify(crawlApiResponseRepository, never()).save(any(CrawlApiResponse.class)); + } + +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingServiceTest.java new file mode 100644 index 00000000..090cee10 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/PrimaryCrawlingServiceTest.java @@ -0,0 +1,7 @@ +package com.hubo.gillajabi.crawl.domain.service; + + + +class PrimaryCrawlingServiceTest +{ +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImplTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImplTest.java new file mode 100644 index 00000000..5cc7ec87 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/WeatherCrawlServiceImplTest.java @@ -0,0 +1,4 @@ +package com.hubo.gillajabi.crawl.domain.service; + +public class WeatherCrawlServiceImplTest { +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceTest.java new file mode 100644 index 00000000..2d5c6d6f --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadCrawlDuruServiceTest.java @@ -0,0 +1,91 @@ +package com.hubo.gillajabi.crawl.domain.service.duru; + +import com.hubo.gillajabi.crawl.domain.service.PrimaryCrawlingService; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; +import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; +import com.hubo.gillajabi.crawl.infrastructure.config.RoadEndpointConfig; +import com.hubo.gillajabi.global.common.dto.ApiProperties; +import com.navercorp.fixturemonkey.FixtureMonkey; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RoadCrawlDuruServiceTest { + + @Mock + private RoadEndpointConfig roadEndpointConfig; + + @Mock + private CrawlApiBuilderHelper crawlApiBuilderHelper; + + @Mock + private PrimaryCrawlingService primaryCrawlingService; + + @InjectMocks + private RoadCrawlDuruServiceImpl crawlDuruService; + + @BeforeEach + void setUp() { + ApiProperties duruApiProperties = new ApiProperties(); + duruApiProperties.setSiteUrl("http://example.com/api"); + when(roadEndpointConfig.getEndpoint(any())).thenReturn(duruApiProperties); + crawlDuruService.init(); + } + +// @Test +// @DisplayName("두루누비 코스 크롤링 테스트") +// void testCrawlCourse() throws URISyntaxException { +// // given +// makeCrawlCourseMock(); +// +// // when +// List courses = crawlDuruService.crawlCourse(); +// +// // then +// assertEquals(1, courses.size()); +// assertEquals("서해랑길 53코스", courses.get(0).getCrsKorNm()); +// } +// +// private void makeCrawlCourseMock() throws URISyntaxException { +// URI uriCoursePage1 = new URI("http://example.com/api/courseList?page=1"); +// +// when(crawlApiBuilderHelper.buildUri(eq("courseList"), any(), eq(1))).thenReturn(uriCoursePage1); +// +// ApiCourseResponse courseResponsePage1 = new ApiCourseResponse(); +// +// when(primaryCrawlingService.crawlPage(eq(ApiCourseResponse.class), eq(uriCoursePage1))).thenReturn(courseResponsePage1); +// } +// +// @Test +// @DisplayName("두루누비 테마 크롤링 테스트") +// void testCrawlTheme() throws URISyntaxException { +// // given +// makeCrawlThemeMock(); +// +// // when +// List themes = crawlDuruService.crawlTheme(); +// +// // then +// assertFalse(themes.isEmpty()); +// assertEquals(1, themes.size()); +// } +// +// private void makeCrawlThemeMock() throws URISyntaxException { +// URI uriThemePage1 = new URI("http://example.com/api/routeList?page=1"); +// +// when(crawlApiBuilderHelper.buildUri(eq("routeList"), any(), eq(1))).thenReturn(uriThemePage1); +// +// ApiThemeResponse themeResponsePage1 = FixtureMonkey.builder().build().giveMeOne(ApiThemeResponse.class); +// +// when(primaryCrawlingService.crawlPage(eq(ApiThemeResponse.class), eq(uriThemePage1))).thenReturn(themeResponsePage1); +// } +} diff --git a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandlerTest.java similarity index 81% rename from src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java rename to src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandlerTest.java index efbafe38..e4f3d3d2 100644 --- a/src/test/java/com/hubo/gillajabi/road/application/service/RoadDuruThemeHandlerTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/domain/service/duru/RoadThemeDuruHandlerTest.java @@ -1,10 +1,7 @@ -package com.hubo.gillajabi.road.application.service; +package com.hubo.gillajabi.crawl.domain.service.duru; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadDuruThemeHandler; import com.hubo.gillajabi.crawl.application.response.RoadCrawlResponse; import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCourseDuruThemeService; -import com.hubo.gillajabi.crawl.domain.service.duru.RoadCrawlDuruServiceImpl; import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiThemeResponse; import com.navercorp.fixturemonkey.FixtureMonkey; @@ -22,7 +19,7 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class RoadDuruThemeHandlerTest { +class RoadThemeDuruHandlerTest { @Mock private RoadCrawlDuruServiceImpl duruCrawlService; @@ -31,7 +28,7 @@ class RoadDuruThemeHandlerTest { private RoadCourseDuruThemeService roadCourseDuruThemeService; @InjectMocks - private RoadDuruThemeHandler roadDuruThemeHandler; + private RoadThemeDuruHandler roadThemeDuruHandler; @Test @DisplayName("두루누비 테마를 제대로 호출") @@ -52,7 +49,7 @@ void testHandle() { when(roadCourseDuruThemeService.saveDuruTheme(anyList())).thenReturn(mockThemes); // when - RoadCrawlResponse.ThemeResult result = roadDuruThemeHandler.handle(); + RoadCrawlResponse.ThemeResult result = roadThemeDuruHandler.handle(); // then assertEquals(mockThemes.size(), result.getThemeCount()); diff --git a/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadEndpointConfigTest.java similarity index 96% rename from src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java rename to src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadEndpointConfigTest.java index c9d3f506..f9dd4454 100644 --- a/src/test/java/com/hubo/gillajabi/road/infraStructure/config/RoadEndpointConfigTest.java +++ b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/RoadEndpointConfigTest.java @@ -1,4 +1,4 @@ -package com.hubo.gillajabi.road.infraStructure.config; +package com.hubo.gillajabi.crawl.infraStructure.config; import com.hubo.gillajabi.crawl.domain.constant.CityCrawlName; import com.hubo.gillajabi.global.common.dto.ApiProperties; diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/WeatherEndpointConfigTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/WeatherEndpointConfigTest.java new file mode 100644 index 00000000..f15b5d54 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/config/WeatherEndpointConfigTest.java @@ -0,0 +1,54 @@ +package com.hubo.gillajabi.crawl.infraStructure.config; + +import com.hubo.gillajabi.crawl.domain.constant.ForecastType; +import com.hubo.gillajabi.crawl.infrastructure.config.WeatherEndpointConfig; +import com.hubo.gillajabi.global.common.dto.ApiProperties; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringBootTest +@EnableConfigurationProperties(WeatherEndpointConfig.class) +@ActiveProfiles("test") +class WeatherEndpointConfigTest { + + @Autowired + private WeatherEndpointConfig weatherEndpointConfig; + + @Test + public void testCurrentWeatherEndpointConfig() { + ApiProperties currentProperties = weatherEndpointConfig.getEndPoint().get(ForecastType.CURRENT); + assertNotNull(currentProperties); + assertEquals("http://example.com", currentProperties.getEndpoint()); + assertEquals("serviceKey", currentProperties.getEncoding()); + assertEquals("serviceKey", currentProperties.getDecoding()); + assertEquals("http://example.com", currentProperties.getSiteUrl()); + } + + @Test + public void testWeatherAlertEndpointConfig() { + ApiProperties alertProperties = weatherEndpointConfig.getEndPoint().get(ForecastType.WEATHER_ALERT); + assertNotNull(alertProperties); + assertEquals("http://example.com", alertProperties.getEndpoint()); + assertEquals("serviceKey", alertProperties.getEncoding()); + assertEquals("serviceKey", alertProperties.getDecoding()); + assertEquals("http://example.com", alertProperties.getSiteUrl()); + } + + @Test + public void testMediumTermWeatherEndpointConfig() { + ApiProperties mediumTermProperties = weatherEndpointConfig.getEndPoint().get(ForecastType.MEDIUM_TERM); + assertNotNull(mediumTermProperties); + assertEquals("http://example.com", mediumTermProperties.getEndpoint()); + assertEquals("serviceKey", mediumTermProperties.getEncoding()); + assertEquals("serviceKey", mediumTermProperties.getDecoding()); + assertEquals("http://example.com", mediumTermProperties.getSiteUrl()); + } + + +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/dto/CourseReqeustTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/dto/CourseReqeustTest.java new file mode 100644 index 00000000..67abdd8a --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/dto/CourseReqeustTest.java @@ -0,0 +1,77 @@ +package com.hubo.gillajabi.crawl.infraStructure.dto; + +import com.hubo.gillajabi.crawl.domain.constant.Province; +import com.hubo.gillajabi.crawl.domain.entity.City; +import com.hubo.gillajabi.crawl.domain.entity.CourseTheme; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CityRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.request.CourseThemeRequest; +import com.hubo.gillajabi.crawl.infrastructure.dto.response.ApiCourseResponse; +import com.navercorp.fixturemonkey.FixtureMonkey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CourseReqeustTest { + + public static FixtureMonkey fixtureMonkey = FixtureMonkey.builder().build(); + + private ApiCourseResponse.Course createApiResponse() { + return fixtureMonkey.giveMeBuilder(ApiCourseResponse.Course.class) + .set("routeIdx", "1") + .set("crsIdx", "1") + .set("crsKorNm", "남파랑길 1코스") + .set("crsDstnc", "5") + .set("crsTotlRqrmHour", "2") + .set("crsLevel", "1") + .set("crsCycle", "비순환형") + .set("crsContents", "남파랑길 1코스는 ...") + .set("crsSummary", "남파랑길 1코스는 ...") + .set("sigun", "경남 김해시") + .sample(); + } + + private City createCity() { + CityRequest cityRequest = CityRequest.of("김해시", Province.GYEONGNAM, "김해"); + return City.createCity(cityRequest); + } + + private static CourseTheme createCourseTheme() { + CourseThemeRequest courseThemeRequest = fixtureMonkey.giveMeOne(CourseThemeRequest.class); + return CourseTheme.createCourseTheme(courseThemeRequest); + } + + @Test + @DisplayName("createCourse에서 잘못된 코스 이름이 들어왔을 때 IllegalArgumentException 발생") + public void createCourse_잘못된_코스_이름_입력시_IllegalArgumentException_발생() { + // given + ApiCourseResponse.Course apiCourseResponse = createApiResponse(); + apiCourseResponse.setCrsKorNm("잘못된이름"); + + // when + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + CourseRequest.of(apiCourseResponse, createCity(), createCourseTheme()); + }); + + // then + String expectedMessage = "잘못된 코스 이름 : " + apiCourseResponse.getCrsKorNm(); + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + @DisplayName("createCourse에서 올바른 코스 이름이 들어왔을때 올바르게 통과") + public void createCourse_올바른_코스_이름_입력시(){ + // given + ApiCourseResponse.Course apiCourseResponse = createApiResponse(); + apiCourseResponse.setCrsKorNm("남파랑길 1코스"); + + // when + CourseRequest courseRequest = CourseRequest.of(apiCourseResponse, createCity(), createCourseTheme()); + + // then + assertTrue(courseRequest.getCourseName().equals(apiCourseResponse.getCrsKorNm())); + } +} diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java new file mode 100644 index 00000000..9d4083b0 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/CrawlApiBuilderHelperTest.java @@ -0,0 +1,125 @@ +//package com.hubo.gillajabi.crawl.infraStructure.util.helper; +// +//import com.hubo.gillajabi.crawl.domain.entity.City; +//import com.hubo.gillajabi.crawl.infrastructure.util.helper.CrawlApiBuilderHelper; +//import com.hubo.gillajabi.global.common.dto.ApiProperties; +//import com.hubo.gillajabi.crawl.infrastructure.dto.response.ValidatableResponse; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +// +//import java.net.URI; +//import java.net.URISyntaxException; +//import java.time.LocalDate; +//import java.time.format.DateTimeFormatter; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.Mockito.*; +// +//@ExtendWith(MockitoExtension.class) +//class CrawlApiBuilderHelperTest { +// +// private CrawlApiBuilderHelper crawlApiBuilderHelper; +// +// private ApiProperties apiProperties; +// +// @Mock +// private ValidatableResponse response; +// +// @Mock +// private City city; +// +// private static final String ENDPOINT_PATH = "testEndpoint"; +// private static final String SITE_URL = "http://example.com/api/{}?serviceKey={serviceKey}&numOfRows={numOfRows}&pageNo={pageNo}"; +// private static final String SERVICE_KEY = "testServiceKey"; +// private static final int PAGE_NO = 1; +// private static final String CITY_CODE = "testCityCode"; +// private static final LocalDate DATE = LocalDate.of(2023, 6, 28); +// private static final int NX = 60; +// private static final int NY = 127; +// +// @BeforeEach +// public void setUp() { +// crawlApiBuilderHelper = new CrawlApiBuilderHelper(); +// +// apiProperties = new ApiProperties(); +// apiProperties.setSiteUrl(SITE_URL); +// apiProperties.setEncoding(SERVICE_KEY); +// +// // when(city.getCityCode()).thenReturn(CITY_CODE); +// } +// +// @Test +// @DisplayName("buildUri 메서드 호출 시, 올바르게 URI 반환") +// public void 유효한_입력일시_올바른_URI_반환() throws URISyntaxException { +// // given +// URI expectedUri = new URI("http://example.com/api/testEndpoint?serviceKey=testServiceKey&numOfRows=100&pageNo=1"); +// +// // when +// URI resultUri = crawlApiBuilderHelper.buildUri(ENDPOINT_PATH, apiProperties, PAGE_NO); +// +// // then +// assertEquals(expectedUri, resultUri); +// } +// +// @Test +// @DisplayName("잘못된 변수로 buildUri 메서드 호출 시, URI 생성 실패") +// public void 유효하지_않은_입력일시_URI생성실패() { +// // given +// String invalidSiteUrl = "http://[invalid-url]/api/{}?serviceKey={serviceKey}&numOfRows={numOfRows}&pageNo={pageNo}"; +// apiProperties.setSiteUrl(invalidSiteUrl); +// +// // when +// IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { +// crawlApiBuilderHelper.buildUri(ENDPOINT_PATH, apiProperties, PAGE_NO); +// }); +// +// //then +// String expectedMessage = "URI 생성 실패"; +// assertTrue(exception.getMessage().contains(expectedMessage)); +// } +// +// @Test +// @DisplayName("validateResponse 메서드 호출 시, response.validate() 메서드 호출") +// public void validateResponse() { +// // given +// doNothing().when(response).validate(); +// +// // when +// crawlApiBuilderHelper.validateResponse(response); +// +// // then +// verify(response, times(1)).validate(); +// } +// +// @Test +// @DisplayName("buildUri (MEDIUM_TERM) 메서드 호출 시, 올바르게 URI 반환") +// public void 유효한_MEDIUM_TERM_입력일시_올바른_URI_반환() throws URISyntaxException { +// // given +// String invalidSiteUrl = "https://apis.data.go.kr/1360000/MidFcstInfoService/{endPath}?serviceKey={serviceKey}&pageNo={pageNo}&numOfRows={numOfRows}&dataType=JSON®Id={cityCode}&tmFc={tmFc} +// apiProperties.setSiteUrl(invalidSiteUrl); +// // when +// URI resultUri = crawlApiBuilderHelper.buildUri(ENDPOINT_PATH, apiProperties, city, PAGE_NO, DATE); +// +// // then +// assertEquals(expectedUri, resultUri); +// } +// +// @Test +// @DisplayName("buildUri (current 날씨) 메서드 호출 시, 올바르게 URI 반환") +// public void 유효한_현재_날씨_입력일시_올바른_URI_반환() throws URISyntaxException { +// // given +// String baseDateStr = DATE.format(DateTimeFormatter.ofPattern("yyyyMMdd")); +// URI expectedUri = new URI("http://example.com/api/testEndpoint?serviceKey=testServiceKey&pageNo=1&numOfRows=100&baseDate=" + baseDateStr + "&nx=" + NX + "&ny=" + NY); +// +// // when +// URI resultUri = crawlApiBuilderHelper.buildUri(apiProperties, NX, NY, DATE, PAGE_NO); +// +// // then +// assertEquals(expectedUri, resultUri); +// } +// +//} diff --git a/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/RoadRoadCrawlResponseParserHelperTest.java b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/RoadRoadCrawlResponseParserHelperTest.java new file mode 100644 index 00000000..af1efcb4 --- /dev/null +++ b/src/test/java/com/hubo/gillajabi/crawl/infraStructure/util/helper/RoadRoadCrawlResponseParserHelperTest.java @@ -0,0 +1,55 @@ +package com.hubo.gillajabi.crawl.infraStructure.util.helper; + +import com.hubo.gillajabi.crawl.infrastructure.util.helper.RoadCrawlResponseParserHelper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class RoadRoadCrawlResponseParserHelperTest { + + @Test + @DisplayName("경남 김해시 -> 김해시로 파싱") + public void 경남_김해시를_김해시로_파싱_성공() { + // Given + String input = "경남 김해시"; + String expected = "김해시"; + + // When + String result = RoadCrawlResponseParserHelper.parseDuruResponseByCity(input); + + // Then + assertEquals(expected, result); + } + + @Test + @DisplayName("경남김해시 공백이 없을경우 -> IllegalArgumentException 에러 발생") + public void 공백이_없는_지역명일때_파싱_실패() { + // Given + String input = "경남김해시"; // 공백이 없음 + + // When + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + RoadCrawlResponseParserHelper.parseDuruResponseByCity(input); + }); + + // Then + String expectedMessage = "잘못된 포맷 형식 : " + input; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + @DisplayName("경남 김해시 -> 경남으로 파싱") + public void 경남_김해시_에서_김해시_파싱_성공() { + // Given + String input = "경남 김해시"; + String expected = "경남"; + + // When + String result = RoadCrawlResponseParserHelper.parseDuruResponseByProvince(input); + + // Then + assertEquals(expected, result); + } +}