diff --git a/src/main/java/backend/airo/api/area_code/AreaCodeController.java b/src/main/java/backend/airo/api/area_code/AreaCodeController.java index b164b3a..47e9b0f 100644 --- a/src/main/java/backend/airo/api/area_code/AreaCodeController.java +++ b/src/main/java/backend/airo/api/area_code/AreaCodeController.java @@ -29,7 +29,7 @@ public Response> getMegaCodes(){ List megaCodes = areaCodeUseCase.getMegaCodeList(); return Response.success( megaCodes.stream().map(list -> - new MegaCodeResponse(list.ctprvnCd(), list.ctprvnNm()) + new MegaCodeResponse(list.getCtprvnCd(), list.getCtprvnNm()) ).toList() ); } diff --git a/src/main/java/backend/airo/api/clutr_fatvl/ClutrFatvlController.java b/src/main/java/backend/airo/api/clutr_fatvl/ClutrFatvlController.java index c35e94c..6692739 100644 --- a/src/main/java/backend/airo/api/clutr_fatvl/ClutrFatvlController.java +++ b/src/main/java/backend/airo/api/clutr_fatvl/ClutrFatvlController.java @@ -30,12 +30,11 @@ public class ClutrFatvlController implements ClutrFatvlControllerSwagger { private final ClutrFatvlUseCase clutrFatvlUseCase; private final AreaCodeCacheService areaCodeCacheService; - @Override @GetMapping("/clutr/fatvl") public Response> getClureFatvlList( - @RequestParam() String megaCode, - @RequestParam() String cityCode, + @RequestParam() Integer megaCode, + @RequestParam() Integer cityCode, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size ) { @@ -45,8 +44,8 @@ public Response> getClureFatvlList( List content = clutrFatvls.getContent().stream().map(list -> ClutrFatvListResponse.create( list, - areaCodeCacheService.getMegaName(Long.valueOf(list.address().megaCodeId())), - areaCodeCacheService.getCityName(Long.valueOf(list.address().ctprvnCodeId()), Long.valueOf(list.address().megaCodeId()))) + areaCodeCacheService.getMegaName(Long.valueOf(list.getAddress().megaCodeId())), + areaCodeCacheService.getCityName(Long.valueOf(list.getAddress().ctprvnCodeId()), Long.valueOf(list.getAddress().megaCodeId()))) ).toList(); return Response.success( new PageResponse<>( @@ -64,6 +63,6 @@ public Response> getClureFatvlList( public Response getClutrFatvlInfo( @RequestParam Long clutrFatvlId) { ClutrFatvl clutrFatvlInfo = clutrFatvlUseCase.getClutrFatvlInfo(clutrFatvlId); - return Response.success(ClutrFatvInfoResponse.create(clutrFatvlInfo)); + return Response.success(ClutrFatvInfoResponse.create(clutrFatvlInfo, null)); } } diff --git a/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvInfoResponse.java b/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvInfoResponse.java index 563e892..d643570 100644 --- a/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvInfoResponse.java +++ b/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvInfoResponse.java @@ -1,73 +1,52 @@ package backend.airo.api.clutr_fatvl.dto; import backend.airo.domain.clure_fatvl.ClutrFatvl; +import backend.airo.domain.clure_fatvl.ClutrFatvlInfo; import backend.airo.domain.clure_fatvl.vo.Address; import backend.airo.domain.clure_fatvl.vo.FestivalPeriod; import lombok.Builder; @Builder public record ClutrFatvInfoResponse( - String id, - - // 축제/행사 이름 - String fstvlNm, - - // 행사 장소 - String opar, - - // 행사 상세 내용 - String fstvlCo, - - // 행사 기간 [시작일, 종료일] - FestivalPeriod period, - - // 행사 주소 [지번, 도로명] - Address address, - - // 주관 기관명(Organizer / 실제 운영) - String mnnstNm, - - // 주최 기관명(Host) - String auspcInsttNm, - - // 후원 기관명(Sponsor) - String suprtInsttNm, - - // 행사 담당 전화번호 + Long contentId, + String title, + String firstImage1, + String firstImage2, + String homepage, + String addr1, + String addr2, + String cat1, + String usetimefestival, + String playTime, + String start, + String end, String phoneNumber, - - // 행사 홈페이지 URL - String homepageUrl, - - // 관련 정보(비고/추가 안내/링크 등) - String relateInfo - -// // 이 데이터(레코드)의 기준/갱신 일자 -// LocalDate referenceDate - -// // 공공데이터포털 제공 기관 코드 -// String insttCode, -// -// // 공공데이터포털 제공 기관명 -// String insttNm + String agelimit, + String clutrFatvlIntro, + String mainProgramInfo, + String guestProgramInfo ) { - public static ClutrFatvInfoResponse create(ClutrFatvl clutrFatvlInfo) { + public static ClutrFatvInfoResponse create(ClutrFatvl clutrFatvl, ClutrFatvlInfo clutrFatvlInfo) { return ClutrFatvInfoResponse.builder() - .id(clutrFatvlInfo.id()) - .fstvlNm(clutrFatvlInfo.fstvlNm()) - .opar(clutrFatvlInfo.opar()) - .fstvlCo(clutrFatvlInfo.fstvlCo()) - .period(clutrFatvlInfo.period()) - .address(clutrFatvlInfo.address()) - .mnnstNm(clutrFatvlInfo.mnnstNm()) - .auspcInsttNm(clutrFatvlInfo.auspcInsttNm()) - .suprtInsttNm(clutrFatvlInfo.suprtInsttNm()) - .phoneNumber(clutrFatvlInfo.phoneNumber()) - .homepageUrl(clutrFatvlInfo.homepageUrl()) - .relateInfo(clutrFatvlInfo.relateInfo()) + .contentId(clutrFatvl.getContentId()) + .title(clutrFatvl.getTitle()) + .firstImage1(clutrFatvl.getFirstImage()) + .firstImage2(clutrFatvl.getFirstImage2()) + .homepage(clutrFatvlInfo.getEventHomePage()) + .addr1(clutrFatvl.getAddress().addr1()) + .addr2(clutrFatvl.getAddress().addr2()) + .cat1(clutrFatvl.getCat1()) + .usetimefestival(clutrFatvlInfo.getUsetimefestival()) + .playTime(clutrFatvlInfo.getPlayTime()) + .start(clutrFatvlInfo.getStart()) + .end(clutrFatvlInfo.getEnd()) + .phoneNumber(clutrFatvlInfo.getPhoneNumber()) + .agelimit(clutrFatvlInfo.getAgelimit()) + .clutrFatvlIntro(clutrFatvlInfo.getClutrFatvlIntro()) + .mainProgramInfo(clutrFatvlInfo.getMainProgramInfo()) + .guestProgramInfo(clutrFatvlInfo.getGuestProgramInfo()) .build(); } - private static String nz(String s) { return s == null ? "" : s; } } diff --git a/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvListResponse.java b/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvListResponse.java index 3440529..583f38a 100644 --- a/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvListResponse.java +++ b/src/main/java/backend/airo/api/clutr_fatvl/dto/ClutrFatvListResponse.java @@ -8,35 +8,20 @@ @Builder public record ClutrFatvListResponse( - String id, - String name, - LocalDate startDate, - LocalDate endDate, - String region, - String place, - String shortDesc, - boolean progressCheck, - boolean periodCheck, - boolean ended + Long contentId, + String title, + String firstImage1, + String firstImage2 ) { public static ClutrFatvListResponse create(ClutrFatvl clutrFatvl, String megaName, String cityName) { return ClutrFatvListResponse.builder() - .id(clutrFatvl.id()) - .name(clutrFatvl.fstvlNm()) - .startDate(clutrFatvl.period().start()) - .endDate(clutrFatvl.period().end()) - .region(addMegaNameCityName(megaName, cityName)) - .place(clutrFatvl.opar()) - .progressCheck(clutrFatvl.period().progressCheck()) - .periodCheck(clutrFatvl.period().periodCheck()) - .ended(clutrFatvl.period().ended()) + .contentId(clutrFatvl.getContentId()) + .title(clutrFatvl.getTitle()) + .firstImage1(clutrFatvl.getFirstImage()) + .firstImage2(clutrFatvl.getFirstImage2()) .build(); } - private static String addMegaNameCityName(String megaName, String cityName) { - return megaName + " " + cityName; - } - } diff --git a/src/main/java/backend/airo/api/global/swagger/ClutrFatvlControllerSwagger.java b/src/main/java/backend/airo/api/global/swagger/ClutrFatvlControllerSwagger.java index dbac19e..cea1805 100644 --- a/src/main/java/backend/airo/api/global/swagger/ClutrFatvlControllerSwagger.java +++ b/src/main/java/backend/airo/api/global/swagger/ClutrFatvlControllerSwagger.java @@ -43,8 +43,8 @@ public interface ClutrFatvlControllerSwagger { ) @GetMapping("/clutr/fatvl") Response> getClureFatvlList( - @RequestParam() String megaCode, - @RequestParam() String cityCode, + @RequestParam() Integer megaCode, + @RequestParam() Integer cityCode, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size ); diff --git a/src/main/java/backend/airo/api/shop/ShopController.java b/src/main/java/backend/airo/api/shop/ShopController.java index 005e21d..ff396ba 100644 --- a/src/main/java/backend/airo/api/shop/ShopController.java +++ b/src/main/java/backend/airo/api/shop/ShopController.java @@ -32,11 +32,11 @@ public class ShopController implements ShopControllerSwagger { @Override @GetMapping("/shop") public Response> getShoplList( - @RequestParam() String megaCode, - @RequestParam() String cityCode, - @RequestParam() String largeCategoryCode, - @RequestParam(defaultValue = "") String middleCategoryCode, - @RequestParam(defaultValue = "") String smallCategoryCode, + @RequestParam() String megaCode, + @RequestParam() String cityCode, + @RequestParam() String largeCategoryCode, + @RequestParam(defaultValue = "") String middleCategoryCode, + @RequestParam(defaultValue = "") String smallCategoryCode, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size ) { diff --git a/src/main/java/backend/airo/api/shop/dto/ShopInfoResponse.java b/src/main/java/backend/airo/api/shop/dto/ShopInfoResponse.java index 0edcaea..314ceb8 100644 --- a/src/main/java/backend/airo/api/shop/dto/ShopInfoResponse.java +++ b/src/main/java/backend/airo/api/shop/dto/ShopInfoResponse.java @@ -1,28 +1,29 @@ package backend.airo.api.shop.dto; import backend.airo.domain.shop.Shop; -import backend.airo.domain.shop.vo.ShopType; +import backend.airo.api.shop.vo.ShopType; import lombok.Builder; @Builder public record ShopInfoResponse( - Long id, - String shopName, - String roadAddr, - String lotAddr, - String flrNo, - String hoNo, - ShopType shopType + Long contentId, + Integer contentTypeId, + String name, + String addr, + String representativeImageURL, + String thumbnailImageURl, + String shopTypeName ) { public static ShopInfoResponse create(Shop shop) { return ShopInfoResponse.builder() - .id(shop.id()) - .shopName(shop.shopName()) - .roadAddr(shop.address().road()) - .lotAddr(shop.address().lot()) - .flrNo(shop.floorInfo().flrNo()) - .hoNo(shop.floorInfo().hoNo()) + .contentId(shop.contentId()) + .contentTypeId(shop.contentTypeId()) + .name(shop.shopName()) + .addr(shop.address().addr()) + .representativeImageURL(shop.representativeImageURL()) + .thumbnailImageURl(shop.thumbnailImageURl()) + .shopTypeName(ShopType.valueOf(shop.industry().indsSclsCd()).getName()) .build(); } diff --git a/src/main/java/backend/airo/api/shop/dto/ShopListResponse.java b/src/main/java/backend/airo/api/shop/dto/ShopListResponse.java index 309aa04..caf3cac 100644 --- a/src/main/java/backend/airo/api/shop/dto/ShopListResponse.java +++ b/src/main/java/backend/airo/api/shop/dto/ShopListResponse.java @@ -1,25 +1,30 @@ package backend.airo.api.shop.dto; import backend.airo.domain.shop.Shop; +import backend.airo.api.shop.vo.ShopType; import lombok.Builder; @Builder public record ShopListResponse( - Long id, + Long contentId, + Integer contentTypeId, String name, - String lotAddr, - String roadAddr, - String indeScleName + String addr, + String representativeImageURL, + String thumbnailImageURl, + String shopTypeName ) { public static ShopListResponse create(Shop shop) { return new ShopListResponse( - shop.id(), + shop.contentId(), + shop.contentTypeId(), shop.shopName(), - shop.address().lot(), - shop.address().road(), - shop.shopType().getTypeName() + shop.address().addr(), + shop.representativeImageURL(), + shop.thumbnailImageURl(), + ShopType.valueOf(shop.industry().indsSclsCd()).getName() ); } diff --git a/src/main/java/backend/airo/api/shop/vo/ShopType.java b/src/main/java/backend/airo/api/shop/vo/ShopType.java new file mode 100644 index 0000000..7095d03 --- /dev/null +++ b/src/main/java/backend/airo/api/shop/vo/ShopType.java @@ -0,0 +1,46 @@ +package backend.airo.api.shop.vo; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum ShopType { + // ---- 음식 ---- + A05("A05", "음식"), + A0502("A0502", "음식점"), + + // 소분류(음식점) + A05020100("A05020100", "한식"), + A05020200("A05020200", "서양식"), + A05020300("A05020300", "일식"), + A05020400("A05020400", "중식"), + A05020700("A05020700", "이색음식점"), + A05020900("A05020900", "카페/전통찻집"), + A05021000("A05021000", "클럽"), + + + // ---- 숙박 ---- + B02("B02", "숙박"), + B0201("B0201", "숙박업"), + + // 소분류(숙박업) + B02010100("B02010100", "관광호텔"), + B02010500("B02010500", "콘도미니엄"), + B02010600("B02010600", "유스호스텔"), + B02010700("B02010700", "펜션"), + B02010900("B02010900", "모텔"), + B02011000("B02011000", "민박"), + B02011100("B02011100", "게스트하우스"), + B02011200("B02011200", "홈스테이"), + B02011300("B02011300", "서비스드레지던스"), + B02011600("B02011600", "한옥"), + + ; + + public enum Level { MAJOR, MID, SUB } + + private final String code; + private final String name; + +} \ No newline at end of file diff --git a/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvl.java b/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvl.java new file mode 100644 index 0000000..3d629cf --- /dev/null +++ b/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvl.java @@ -0,0 +1,25 @@ +package backend.airo.application.clure_fatvl.dto; + + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.time.LocalDate; + +public record OpenApiClutrFatvl( + Long contentId, + Integer contenttypeId, + String title, + Double lat, + Double lon, + String addr1, + String addr2, + Integer megaCodeId, + Integer ctprvnCodeId, + String phoneNumber, + String cat1, + String firstImage, + String firstImage2, + @JsonFormat(pattern = "yyyyMMddHHmmss") + LocalDate modifiedDate + ) { +} diff --git a/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlInfo.java b/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlInfo.java deleted file mode 100644 index 601e201..0000000 --- a/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package backend.airo.application.clure_fatvl.dto; - -import java.time.LocalDate; - -public record OpenApiClutrFatvlInfo( - String fstvlNm, - String opar, - String fstvlCo, - LocalDate start, - LocalDate end, - Double lat, - Double lon, - String road, - String lot, - String mnnstNm, - String auspcInsttNm, - String suprtInsttNm, - String phoneNumber, - String homepageUrl, - String relateInfo, - LocalDate referenceDate, - String insttCode, - String insttNm - -) { -} diff --git a/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlResponse.java b/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlResponse.java index 477272d..f84def4 100644 --- a/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlResponse.java +++ b/src/main/java/backend/airo/application/clure_fatvl/dto/OpenApiClutrFatvlResponse.java @@ -5,7 +5,7 @@ import java.util.List; public record OpenApiClutrFatvlResponse( - List openApiClutrFatvlInfos, + List openApiClutrFatvls, String resultCode, String numOfRows, String pageNo, diff --git a/src/main/java/backend/airo/application/clure_fatvl/usecase/ClutrFatvlUseCase.java b/src/main/java/backend/airo/application/clure_fatvl/usecase/ClutrFatvlUseCase.java index 9a84e55..5d24a60 100644 --- a/src/main/java/backend/airo/application/clure_fatvl/usecase/ClutrFatvlUseCase.java +++ b/src/main/java/backend/airo/application/clure_fatvl/usecase/ClutrFatvlUseCase.java @@ -2,6 +2,7 @@ import backend.airo.cache.clutr_fatvl.ClutrFatvlCacheService; import backend.airo.domain.clure_fatvl.ClutrFatvl; +import backend.airo.domain.clure_fatvl.query.GetClutrFatvlInfoQuery; import backend.airo.domain.clure_fatvl.query.GetClutrFatvlListQuery; import backend.airo.domain.clure_fatvl.query.GetClutrFatvlQuery; import lombok.RequiredArgsConstructor; @@ -20,7 +21,7 @@ public ClutrFatvl getClutrFatvlInfo(Long clutrFatvlId) { return clutrFatvlCacheService.getClutrFatvl(clutrFatvlId); } - public Page getClutrFatvlList(String megaName, String cityName, Pageable pageable) { + public Page getClutrFatvlList(Integer megaName, Integer cityName, Pageable pageable) { return getClutrFatvlListQuery.handle(megaName, cityName, pageable); } diff --git a/src/main/java/backend/airo/application/post/usecase/PostUseCase.java b/src/main/java/backend/airo/application/post/usecase/PostUseCase.java index a93d532..c2ec66c 100644 --- a/src/main/java/backend/airo/application/post/usecase/PostUseCase.java +++ b/src/main/java/backend/airo/application/post/usecase/PostUseCase.java @@ -68,8 +68,6 @@ public Post createPost(PostCreateRequest request, Long userId) { - - public PostDetailResponse getPostDetail(Long postId, Long requesterId) { log.debug("게시물 조회: id={}, requesterId={}", postId, requesterId); Post post = getPostQueryService.handle(postId); diff --git a/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlFetcher.java b/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlFetcher.java index 0009876..2c20052 100644 --- a/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlFetcher.java +++ b/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlFetcher.java @@ -12,7 +12,7 @@ public class ClutrFatvlFetcher { private final ClureFatvlPort clureFatvlPort; - public OpenApiClutrFatvlResponse fetchClutrFatvl(String page, String pageSize, String startDate) { - return clureFatvlPort.getOpenApiClureFatvl(page, pageSize, startDate); + public OpenApiClutrFatvlResponse fetchClutrFatvl(String page, String contentId, String startDate) { + return clureFatvlPort.getOpenApiClureFatvl(page, contentId, startDate); } } diff --git a/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlJobConfiguration.java b/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlJobConfiguration.java index ba8b004..090818d 100644 --- a/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlJobConfiguration.java +++ b/src/main/java/backend/airo/batch/jobs/cure_fatvl/ClutrFatvlJobConfiguration.java @@ -1,8 +1,7 @@ package backend.airo.batch.jobs.cure_fatvl; -import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlInfo; +import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvl; import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlResponse; -import backend.airo.cache.vo.AreaName; import backend.airo.cache.area_code.AreaCodeCacheService; import backend.airo.domain.clure_fatvl.ClutrFatvl; import backend.airo.persistence.clutrfatvl.repository.ClutrFatvlBulkRepository; @@ -24,22 +23,21 @@ import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.*; -import static backend.airo.batch.utils.ParsingAreaCode.areaNameParsing; - @Configuration @RequiredArgsConstructor @Slf4j public class ClutrFatvlJobConfiguration { - public static final String JOB_NAME = "ClutrFatvlJob"; + private static final String JOB_NAME = "ClutrFatvlJob"; + private static final String CONTENT_ID = "15"; private final JobRepository repo; private final PlatformTransactionManager tx; private final ClutrFatvlFetcher clutrFatvlFetcher; private final ClutrFatvlBulkRepository clutrFatvlBulkRepository; - private final AreaCodeCacheService areaCodeCacheService; // === Job === @Bean(name = JOB_NAME) @@ -55,13 +53,13 @@ public Job clutrFatvlJob(Step clutrFatvlStep, ClutrFatvlJobListener listener, No // === step === @Bean(name = JOB_NAME + ".step") public Step clutrFatvlStep( - ItemStreamReader> reader, - ItemProcessor, List> processor, + ItemStreamReader> reader, + ItemProcessor, List> processor, ItemWriter> writer, @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}") int chunkSize ) { return new StepBuilder(JOB_NAME + ".step", repo) - ., List>chunk(chunkSize, tx) // 한 번에 10개의 List (최대 10,000건) + ., List>chunk(chunkSize, tx) // 한 번에 10개의 List (최대 10,000건) .reader(reader) .processor(processor) .writer(writer) @@ -72,20 +70,23 @@ public Step clutrFatvlStep( // === Reader === @Bean(name = JOB_NAME + ".reader") @StepScope - public ItemStreamReader> clutrReader( + public ItemStreamReader> clutrReader( @Value("#{jobParameters['pageSize'] ?: 1000}") Integer pageSize) { return new ItemStreamReader<>() { - private LocalDate current = LocalDate.now(ZoneId.of("Asia/Seoul")); - private final LocalDate end = current.plusMonths(6); + private final LocalDate getNowDate = LocalDate.now(ZoneId.of("Asia/Seoul")); + private final DateTimeFormatter YMD = DateTimeFormatter.BASIC_ISO_DATE; + + private LocalDate current = getNowDate.minusMonths(6); + private final LocalDate end = getNowDate; private boolean finished = false; private int page = 1; @Override - public List read() { + public List read() { if (finished) return null; - List buffer = new ArrayList<>(); + List buffer = new ArrayList<>(); while (buffer.size() < 1000 && !finished) { if (current.isAfter(end)) { finished = true; @@ -94,17 +95,17 @@ public List read() { OpenApiClutrFatvlResponse resp = clutrFatvlFetcher.fetchClutrFatvl( String.valueOf(page), - String.valueOf(pageSize), - current.toString() + CONTENT_ID, + current.format(YMD) ); - if (resp.resultCode() == null || !"00".equals(resp.resultCode())) { + if (resp.resultCode() == null || !"0000".equals(resp.resultCode())) { current = current.plusDays(1); page = 1; continue; } - List items = resp.openApiClutrFatvlInfos(); + List items = resp.openApiClutrFatvls(); if (items == null || items.isEmpty()) { current = current.plusDays(1); page = 1; @@ -134,15 +135,11 @@ public List read() { // === Processor === @Bean(name = JOB_NAME + ".processor") - public ItemProcessor, List> clutrProcessor() { + public ItemProcessor, List> clutrProcessor() { return items -> items.stream() .map(item -> { try { - AreaName region = areaNameParsing(item.road(), item.lot()); - Long megaCode = areaCodeCacheService.getMegaCode(region.mega()); - System.out.println("Area Region :: " + region.city() + " || code :: " + megaCode ); - Long cityCode = areaCodeCacheService.getCityCode(megaCode, region.city()); - return ClutrFatvl.create(item, megaCode, cityCode); + return ClutrFatvl.create(item); } catch (Exception e) { log.error("Processor 예외 발생: {}", e.getMessage(), e); return null; diff --git a/src/main/java/backend/airo/domain/area_code/MegaCode.java b/src/main/java/backend/airo/domain/area_code/MegaCode.java index ebcbc68..563006b 100644 --- a/src/main/java/backend/airo/domain/area_code/MegaCode.java +++ b/src/main/java/backend/airo/domain/area_code/MegaCode.java @@ -1,15 +1,14 @@ package backend.airo.domain.area_code; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; -public record MegaCode( - Long ctprvnCd, - String ctprvnNm) { - @JsonCreator - public MegaCode(@JsonProperty("ctprvnCd") Long ctprvnCd, - @JsonProperty("ctprvnNm") String ctprvnNm) { +@Getter +public class MegaCode { + private final Long ctprvnCd; + private final String ctprvnNm; + + public MegaCode(Long ctprvnCd, + String ctprvnNm) { this.ctprvnCd = ctprvnCd; this.ctprvnNm = ctprvnNm; } diff --git a/src/main/java/backend/airo/domain/area_code/command/DeleteAllClutrFatvlByDateCommand.java b/src/main/java/backend/airo/domain/area_code/command/DeleteAllClutrFatvlByDateCommand.java deleted file mode 100644 index f43dca2..0000000 --- a/src/main/java/backend/airo/domain/area_code/command/DeleteAllClutrFatvlByDateCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package backend.airo.domain.area_code.command; - -import backend.airo.domain.clure_fatvl.repository.ClutrFatvlRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -import java.time.LocalDate; - -@Component -@RequiredArgsConstructor -public class DeleteAllClutrFatvlByDateCommand { - - private final ClutrFatvlRepository clutrFatvlRepository; - - public void handle(LocalDate start, LocalDate end) { - clutrFatvlRepository.deleteAllByDate(start, end); - } - -} diff --git a/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvl.java b/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvl.java index 4674721..0437e3b 100644 --- a/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvl.java +++ b/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvl.java @@ -1,51 +1,77 @@ package backend.airo.domain.clure_fatvl; -import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlInfo; +import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvl; +import backend.airo.domain.clure_fatvl.utils.PhoneNormalizer; import backend.airo.domain.clure_fatvl.vo.Address; -import backend.airo.domain.clure_fatvl.vo.FestivalPeriod; import backend.airo.domain.clure_fatvl.vo.GeoPoint; +import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.Embedded; import lombok.Builder; +import lombok.Getter; +import lombok.ToString; import java.time.LocalDate; +import java.util.List; -@Builder -public record ClutrFatvl( - String id, - String fstvlNm, - String opar, - String fstvlCo, - @Embedded FestivalPeriod period, - @Embedded GeoPoint location, - @Embedded Address address, - String mnnstNm, - String auspcInsttNm, - String suprtInsttNm, - String phoneNumber, - String homepageUrl, - String relateInfo, - LocalDate referenceDate, - String insttCode, - String insttNm) -{ - public static ClutrFatvl create(OpenApiClutrFatvlInfo dto, Long megaCode, Long cityCode) { +@Getter +@ToString +public class ClutrFatvl { + + private final Long contentId; + + private final Integer contenttypeId; + + private final String title; + + @Embedded + private final GeoPoint location; + + @Embedded + private final Address address; + + private final List phoneNumber; + + private final String cat1; + + private final String firstImage; + + private final String firstImage2; + + @JsonFormat(pattern = "yyyyMMdd") + private final LocalDate modifiedDate; + + @Builder + + public ClutrFatvl(Long contentId, Integer contenttypeId, String title, GeoPoint location, Address address, List phoneNumber, String cat1, String firstImage, String firstImage2, LocalDate modifiedDate) { + this.contentId = contentId; + this.contenttypeId = contenttypeId; + this.title = title; + this.location = location; + this.address = address; + this.phoneNumber = phoneNumber; + this.cat1 = cat1; + this.firstImage = firstImage; + this.firstImage2 = firstImage2; + this.modifiedDate = modifiedDate; + } + + + + public static ClutrFatvl create(OpenApiClutrFatvl dto) { return ClutrFatvl.builder() - .fstvlNm(dto.fstvlNm()) - .opar(dto.opar()) - .fstvlCo(dto.fstvlCo()) - .period(new FestivalPeriod(dto.start(), dto.end())) - .location(new GeoPoint(dto.lat(), dto.lon())) - .address(new Address(dto.road(), dto.lot(), String.valueOf(megaCode), String.valueOf(cityCode))) - .mnnstNm(dto.mnnstNm()) - .auspcInsttNm(dto.auspcInsttNm()) - .suprtInsttNm(dto.suprtInsttNm()) - .phoneNumber(dto.phoneNumber()) - .homepageUrl(dto.homepageUrl()) - .relateInfo(dto.relateInfo()) - .referenceDate(dto.referenceDate()) - .insttCode(dto.insttCode()) - .insttNm(dto.insttNm()) + .contentId(dto.contentId()) + .contenttypeId(dto.contenttypeId()) + .title(dto.title()) + .location(new GeoPoint(dto.lat(),dto.lon())) + .address(new Address(dto.addr1(), dto.addr2(), dto.megaCodeId(), dto.ctprvnCodeId())) + .phoneNumber(PhoneNormalizer.allPhones(dto.phoneNumber())) + .cat1(dto.cat1()) + .firstImage(dto.firstImage()) + .firstImage2(dto.firstImage2()) + .modifiedDate(dto.modifiedDate()) .build(); } + + } diff --git a/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvlInfo.java b/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvlInfo.java new file mode 100644 index 0000000..ef5b6a3 --- /dev/null +++ b/src/main/java/backend/airo/domain/clure_fatvl/ClutrFatvlInfo.java @@ -0,0 +1,65 @@ +package backend.airo.domain.clure_fatvl; + +import backend.airo.domain.clure_fatvl.vo.FestivalPeriod; +import jakarta.persistence.Embedded; +import lombok.Builder; +import lombok.Getter; + + +@Getter +public class ClutrFatvlInfo { + + private final String contentid; + @Embedded + private final FestivalPeriod period; + + private final String usetimefestival; + private final String playTime; + private final String start; + private final String end; + private final String phoneNumber; + private final String agelimit; + private final String clutrFatvlIntro; + private final String mainProgramInfo; + private final String guestProgramInfo; + private final String eventHomePage; + private final String eventPlace; + + + @Builder + public ClutrFatvlInfo(String contentid, FestivalPeriod period, String usetimefestival, String playTime, String start, String end, String phoneNumber, String agelimit, String clutrFatvlIntro, String mainProgramInfo, String guestProgramInfo, String eventHomePage, String eventPlace) { + this.contentid = contentid; + this.period = period; + this.usetimefestival = usetimefestival; + this.playTime = playTime; + this.start = start; + this.end = end; + this.phoneNumber = phoneNumber; + this.agelimit = agelimit; + this.clutrFatvlIntro = clutrFatvlIntro; + this.mainProgramInfo = mainProgramInfo; + this.guestProgramInfo = guestProgramInfo; + this.eventHomePage = eventHomePage; + this.eventPlace = eventPlace; + } + + @Override + public String toString() { + return "ClutrFatvlInfo{" + + "contentid='" + contentid + '\'' + + ", period=" + period + + ", usetimefestival='" + usetimefestival + '\'' + + ", playTime='" + playTime + '\'' + + ", start='" + start + '\'' + + ", end='" + end + '\'' + + ", phoneNumber='" + phoneNumber + '\'' + + ", agelimit='" + agelimit + '\'' + + ", clutrFatvlIntro='" + clutrFatvlIntro + '\'' + + ", mainProgramInfo='" + mainProgramInfo + '\'' + + ", guestProgramInfo='" + guestProgramInfo + '\'' + + ", eventHomePage='" + eventHomePage + '\'' + + ", eventPlace='" + eventPlace + '\'' + + '}'; + } +} + diff --git a/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlInfoQuery.java b/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlInfoQuery.java new file mode 100644 index 0000000..6aa7bcc --- /dev/null +++ b/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlInfoQuery.java @@ -0,0 +1,18 @@ +package backend.airo.domain.clure_fatvl.query; + + +import backend.airo.domain.clure_fatvl.ClutrFatvlInfo; +import backend.airo.domain.clure_fatvl.repository.ClturFatvlnfoRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class GetClutrFatvlInfoQuery { + + private final ClturFatvlnfoRepository clturFatvlnfoRepository; + + public ClutrFatvlInfo handle(Long contentId) { + return clturFatvlnfoRepository.findById(contentId); + } +} diff --git a/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlListQuery.java b/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlListQuery.java index 65edd89..f900003 100644 --- a/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlListQuery.java +++ b/src/main/java/backend/airo/domain/clure_fatvl/query/GetClutrFatvlListQuery.java @@ -13,7 +13,7 @@ public class GetClutrFatvlListQuery { private final ClutrFatvlRepository clutrFatvlRepository; - public Page handle(String megaName, String cityName, Pageable pageable) { + public Page handle(Integer megaName, Integer cityName, Pageable pageable) { return clutrFatvlRepository.findAll(megaName, cityName, pageable); } diff --git a/src/main/java/backend/airo/domain/clure_fatvl/repository/ClturFatvlnfoRepository.java b/src/main/java/backend/airo/domain/clure_fatvl/repository/ClturFatvlnfoRepository.java new file mode 100644 index 0000000..3fae1a8 --- /dev/null +++ b/src/main/java/backend/airo/domain/clure_fatvl/repository/ClturFatvlnfoRepository.java @@ -0,0 +1,7 @@ +package backend.airo.domain.clure_fatvl.repository; + +import backend.airo.domain.AggregateSupport; +import backend.airo.domain.clure_fatvl.ClutrFatvlInfo; + +public interface ClturFatvlnfoRepository extends AggregateSupport { +} diff --git a/src/main/java/backend/airo/domain/clure_fatvl/repository/ClutrFatvlRepository.java b/src/main/java/backend/airo/domain/clure_fatvl/repository/ClutrFatvlRepository.java index 0f3ead6..ab7126c 100644 --- a/src/main/java/backend/airo/domain/clure_fatvl/repository/ClutrFatvlRepository.java +++ b/src/main/java/backend/airo/domain/clure_fatvl/repository/ClutrFatvlRepository.java @@ -10,8 +10,7 @@ public interface ClutrFatvlRepository extends AggregateSupport { - Page findAll(String megaName, String cityName, Pageable pageable); + Page findAll(Integer megaName, Integer cityName, Pageable pageable); - void deleteAllByDate(LocalDate start,LocalDate end); } \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/clure_fatvl/utils/PhoneNormalizer.java b/src/main/java/backend/airo/domain/clure_fatvl/utils/PhoneNormalizer.java new file mode 100644 index 0000000..fa247aa --- /dev/null +++ b/src/main/java/backend/airo/domain/clure_fatvl/utils/PhoneNormalizer.java @@ -0,0 +1,37 @@ +package backend.airo.domain.clure_fatvl.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PhoneNormalizer { + private static final Pattern BR = Pattern.compile("(?i)"); + private static final Pattern PHONE = Pattern.compile("\\+?\\d[\\d\\s\\-()]{6,}\\d"); + + public static List allPhones(String raw) { + if (raw == null) return List.of(); + String s = BR.matcher(raw).replaceAll(","); + Matcher m = PHONE.matcher(s); + List out = new ArrayList<>(); + while (m.find()) { + String local = toLocalDigits(m.group()); + if (local != null) out.add(local); + } + return out.stream().distinct().limit(5).toList(); + } + + private static String toLocalDigits(String token) { + if (token == null) return null; + String digits = token.replaceAll("\\D", ""); // 숫자만 + + if (digits.startsWith("82") && !digits.startsWith("820")) digits = "0" + digits.substring(2); + if (digits.startsWith("820")) digits = "0" + digits.substring(3); + + if (!digits.startsWith("0")) return null; // 국내형만 허용 + if (digits.length() < 8 || digits.length() > 13) return null; // 대략적 길이 필터 + return digits; + } + + +} \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/clure_fatvl/vo/Address.java b/src/main/java/backend/airo/domain/clure_fatvl/vo/Address.java index 9536d85..beec8dc 100644 --- a/src/main/java/backend/airo/domain/clure_fatvl/vo/Address.java +++ b/src/main/java/backend/airo/domain/clure_fatvl/vo/Address.java @@ -5,20 +5,12 @@ @Embeddable public record Address( - @Column(name = "road_addr", length = 512) - String road, - @Column(name = "lot_addr", length = 512) - String lot, - String megaCodeId, - String ctprvnCodeId + @Column(name = "addr1", length = 512) + String addr1, + @Column(name = "addr2", length = 512) + String addr2, + Integer megaCodeId, + Integer ctprvnCodeId ) { - public String checkAddress() { - if (road.isEmpty() && lot.isEmpty()) { - return "주소가 없습니다. "; - } - if (road.isEmpty()) { - return lot; - } - return road; - } + } \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/clure_fatvl/vo/ClutrFatvlPhoneNumber.java b/src/main/java/backend/airo/domain/clure_fatvl/vo/ClutrFatvlPhoneNumber.java new file mode 100644 index 0000000..791c4ef --- /dev/null +++ b/src/main/java/backend/airo/domain/clure_fatvl/vo/ClutrFatvlPhoneNumber.java @@ -0,0 +1,10 @@ +package backend.airo.domain.clure_fatvl.vo; + +public record ClutrFatvlPhoneNumber( + + Long contentId, + int seq, + String phoneNumber + +) { +} diff --git a/src/main/java/backend/airo/domain/shop/Shop.java b/src/main/java/backend/airo/domain/shop/Shop.java index 9924d73..d696781 100644 --- a/src/main/java/backend/airo/domain/shop/Shop.java +++ b/src/main/java/backend/airo/domain/shop/Shop.java @@ -2,24 +2,28 @@ import backend.airo.domain.shop.vo.*; import jakarta.persistence.Embedded; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import lombok.Getter; +/** + * @param industry 업종 코드 묶음 + * @param region 행정 코드 + * @param address 주소 묶음 + * @param location 좌표 묶음 + */ public record Shop( - Long id, + Long contentId, + Integer contentTypeId, String shopName, + @Embedded IndustryCodes industry, + @Embedded RegionCodes region, + @Embedded ShopAddress address, + @Embedded ShopGeoPoint location, - FloorInfo floorInfo, - ShopType shopType, - String brchNm + String representativeImageURL, + String thumbnailImageURl ) { - public Shop(String shopName, IndustryCodes industry, RegionCodes region, - ShopAddress address, ShopGeoPoint location, FloorInfo floorInfo, - ShopType shopType, String brchNm) { - this(null, shopName, industry, region, address, location, floorInfo, shopType, brchNm); - } + } diff --git a/src/main/java/backend/airo/domain/shop/port/OpenApiShopPort.java b/src/main/java/backend/airo/domain/shop/port/OpenApiShopPort.java index 7d941a1..e8eec8d 100644 --- a/src/main/java/backend/airo/domain/shop/port/OpenApiShopPort.java +++ b/src/main/java/backend/airo/domain/shop/port/OpenApiShopPort.java @@ -4,6 +4,6 @@ public interface OpenApiShopPort { - ShopPage getShopData(String pageNo, String numOfRows, String divId, String fstvlEndDate); + ShopPage getShopData(String pageNo, String contentTypeId, String megaCode); -} +} \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/shop/vo/IndustryCodes.java b/src/main/java/backend/airo/domain/shop/vo/IndustryCodes.java index 7a82917..aba3fd4 100644 --- a/src/main/java/backend/airo/domain/shop/vo/IndustryCodes.java +++ b/src/main/java/backend/airo/domain/shop/vo/IndustryCodes.java @@ -5,12 +5,11 @@ @Embeddable public record IndustryCodes( - @Column(name = "ksic_code", length = 6, nullable = false) - String ksicCode, - @Column(name = "inds_lcls_cd", length = 2, nullable = false) + + @Column(name = "inds_lcls_cd", length = 4, nullable = false) String indsLclsCd, - @Column(name = "inds_mcls_cd", length = 4, nullable = false) + @Column(name = "inds_mcls_cd", length = 8, nullable = false) String indsMclsCd, - @Column(name = "inds_scls_cd", length = 7, nullable = false) + @Column(name = "inds_scls_cd", length = 14, nullable = false) String indsSclsCd ) {} diff --git a/src/main/java/backend/airo/domain/shop/vo/RegionCodes.java b/src/main/java/backend/airo/domain/shop/vo/RegionCodes.java index 3e5c9f6..d572e5f 100644 --- a/src/main/java/backend/airo/domain/shop/vo/RegionCodes.java +++ b/src/main/java/backend/airo/domain/shop/vo/RegionCodes.java @@ -6,7 +6,5 @@ @Embeddable public record RegionCodes( String ctprvnCd, - String signguCd, - String adongCd, - String ldongCd + String signguCd ) {} \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/shop/vo/ShopAddress.java b/src/main/java/backend/airo/domain/shop/vo/ShopAddress.java index 0fb8504..5b29192 100644 --- a/src/main/java/backend/airo/domain/shop/vo/ShopAddress.java +++ b/src/main/java/backend/airo/domain/shop/vo/ShopAddress.java @@ -6,18 +6,8 @@ @Embeddable public record ShopAddress( @Column(name = "road_addr", length = 512) - String road, + String addr, @Column(name = "lot_addr", length = 512) - String lot, - String newZipcd + String addrInfo ) { - public String checkAddress() { - if (road.isEmpty() && lot.isEmpty()) { - return "주소가 없습니다. "; - } - if (road.isEmpty()) { - return lot; - } - return road; - } } \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/shop/vo/ShopType.java b/src/main/java/backend/airo/domain/shop/vo/ShopType.java index de126a5..5ac5681 100644 --- a/src/main/java/backend/airo/domain/shop/vo/ShopType.java +++ b/src/main/java/backend/airo/domain/shop/vo/ShopType.java @@ -1,16 +1,16 @@ package backend.airo.domain.shop.vo; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; import lombok.Getter; import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor -@Getter -public enum ShopType { +@Embeddable +public record ShopType( + @Column(name = "road_addr", length = 512) + String road, + @Column(name = "lot_addr", length = 512) + String lot +) { - I1("숙박"), I2("음식") - ; - - - private final String typeName; - // I1 -> 숙박업, I2 -> 음식점업 -} +} \ No newline at end of file diff --git a/src/main/java/backend/airo/gerbege/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java b/src/main/java/backend/airo/gerbege/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java new file mode 100644 index 0000000..c056678 --- /dev/null +++ b/src/main/java/backend/airo/gerbege/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java @@ -0,0 +1,52 @@ +//package backend.airo.infra.open_api.clure_fatvl.adapter; +// +//import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlInfo; +//import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlResponse; +//import backend.airo.domain.clure_fatvl.port.ClureFatvlPort; +//import backend.airo.infra.open_api.clure_fatvl.client.OpenApiClureFatvlFeignClient; +//import backend.airo.infra.open_api.clure_fatvl.dto.OpenApiClureFatvlResponse; +//import backend.airo.infra.open_api.clure_fatvl.vo.ClutrFatvlInfo; +//import lombok.RequiredArgsConstructor; +//import org.springframework.stereotype.Service; +// +//import java.util.List; +// +//@Service +//@RequiredArgsConstructor +//public class OpenApiClureFatvlAdapter implements ClureFatvlPort { +// +// private final OpenApiClureFatvlFeignClient openApiClureFatvlFeignClient; +// +// public OpenApiClutrFatvlResponse getOpenApiClureFatvl(String page, String pageSize, String startDate) { +// OpenApiClureFatvlResponse clutrFatvlInfo = openApiClureFatvlFeignClient.getClutrFatvlInfo(page, pageSize, startDate); +// return new OpenApiClutrFatvlResponse( +// clutrFatvlInfo.body() != null +// ? clutrFatvlInfo.items().stream().map(list -> +// new OpenApiClutrFatvlInfo( +// list.fstvlNm(), +// list.opar(), +// list.fstvlCo(), +// list.fstvlStartDate(), +// list.fstvlEndDate(), +// list.latitude(), +// list.longitude(), +// list.rdnmadr(), +// list.lnmadr(), +// list.mnnstNm(), +// list.auspcInsttNm(), +// list.suprtInsttNm(), +// list.phoneNumber(), +// list.homepageUrl(), +// list.relateInfo(), +// list.referenceDate(), +// list.insttCode(), +// list.insttNm() +// )).toList() +// : List.of(), +// clutrFatvlInfo.header().resultCode(), +// clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().numOfRows() : String.valueOf(0), +// clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().pageNo() : String.valueOf(0), +// clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().totalCount() : String.valueOf(0) +// ); +// } +//} diff --git a/src/main/java/backend/airo/gerbege/clure_fatvl/client/OpenApiClureFatvlFeignClient.java b/src/main/java/backend/airo/gerbege/clure_fatvl/client/OpenApiClureFatvlFeignClient.java new file mode 100644 index 0000000..16125ae --- /dev/null +++ b/src/main/java/backend/airo/gerbege/clure_fatvl/client/OpenApiClureFatvlFeignClient.java @@ -0,0 +1,28 @@ +//package backend.airo.infra.open_api.clure_fatvl.client; +// +//import backend.airo.infra.open_api.clure_fatvl.dto.OpenApiClureFatvlResponse; +//import backend.airo.infra.open_api.clure_fatvl.vo.ClutrFatvlInfo; +//import backend.airo.infra.open_api.rural_ex.config.OpenApiFeignClientConfiguration; +//import org.springframework.cloud.openfeign.FeignClient; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.RequestParam; +// +///** +// * 문화체육관광부에서 제공하는 전국문화축제표준 데이터(Open API)를 이용한 행사, 축제 등 데이터 수집 +// * ... +// */ +//@FeignClient( +// name = "openApi-clutr-fstvl", +// url = "http://api.data.go.kr/openapi", +// configuration = OpenApiFeignClientConfiguration.class) +//public interface OpenApiClureFatvlFeignClient { +// +// @GetMapping("/tn_pubr_public_cltur_fstvl_api") +// OpenApiClureFatvlResponse getClutrFatvlInfo( +// @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, +// @RequestParam(value = "numOfRows", defaultValue = "10000", required = false) String numOfRows, +// @RequestParam(value = "fstvlStartDate") String fstvlStartDate +//// @RequestParam(value = "fstvlEndDate", required = false) String fstvlEndDate +// ); +// +//} diff --git a/src/main/java/backend/airo/gerbege/clure_fatvl/dto/OpenApiClureFatvlResponse.java b/src/main/java/backend/airo/gerbege/clure_fatvl/dto/OpenApiClureFatvlResponse.java new file mode 100644 index 0000000..e9440df --- /dev/null +++ b/src/main/java/backend/airo/gerbege/clure_fatvl/dto/OpenApiClureFatvlResponse.java @@ -0,0 +1,49 @@ +//package backend.airo.infra.open_api.clure_fatvl.dto; +// +//import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +//import com.fasterxml.jackson.annotation.JsonProperty; +// +//import java.util.List; +// +//@JsonIgnoreProperties(ignoreUnknown = true) +//public record OpenApiClureFatvlResponse( +// @JsonProperty("response") Response response +//) { +// +// @JsonIgnoreProperties(ignoreUnknown = true) +// public record Response( +// @JsonProperty("header") Header header, +// @JsonProperty("body") Body body +// ) { +// } +// +// @JsonIgnoreProperties(ignoreUnknown = true) +// public record Header( +// @JsonProperty("resultCode") String resultCode, +// @JsonProperty("resultMsg") String resultMsg, +// @JsonProperty("type") String type // 응답에 있으므로 추가(없어도 무시 가능) +// ) { +// } +// +// @JsonIgnoreProperties(ignoreUnknown = true) +// public record Body( +// @JsonProperty("items") List items, +// @JsonProperty("numOfRows") String numOfRows, // JSON이 문자열이므로 String으로 받는 게 안전 +// @JsonProperty("pageNo") String pageNo, +// @JsonProperty("totalCount") String totalCount +// ) { +// } +// +// /** 편의 메서드 */ +// public List items() { +// return response().body().items(); +// } +// +// public Body body() { +// return response().body(); +// } +// +// public Header header() { +// return response.header(); +// } +//} diff --git a/src/main/java/backend/airo/gerbege/clure_fatvl/vo/ClutrFatvlInfo.java b/src/main/java/backend/airo/gerbege/clure_fatvl/vo/ClutrFatvlInfo.java new file mode 100644 index 0000000..9be5b24 --- /dev/null +++ b/src/main/java/backend/airo/gerbege/clure_fatvl/vo/ClutrFatvlInfo.java @@ -0,0 +1,84 @@ +//package backend.airo.infra.open_api.clure_fatvl.vo; +// +//import com.fasterxml.jackson.annotation.*; +// +//import java.time.LocalDate; +// +//@JsonIgnoreProperties(ignoreUnknown = true) +//public record ClutrFatvlInfo( +// @JsonProperty("fstvlNm") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String fstvlNm, +// +// @JsonProperty("opar") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String opar, +// +// @JsonProperty("fstvlStartDate") +// @JsonFormat(pattern = "yyyy-MM-dd") +// LocalDate fstvlStartDate, +// +// @JsonProperty("fstvlEndDate") +// @JsonFormat(pattern = "yyyy-MM-dd") +// LocalDate fstvlEndDate, +// +// @JsonProperty("fstvlCo") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String fstvlCo, +// +// @JsonProperty("mnnstNm") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String mnnstNm, +// +// @JsonProperty("auspcInsttNm") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String auspcInsttNm, +// +// @JsonProperty("suprtInsttNm") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String suprtInsttNm, +// +// @JsonProperty("phoneNumber") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String phoneNumber, +// +// @JsonProperty("homepageUrl") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String homepageUrl, +// +// @JsonProperty("relateInfo") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String relateInfo, +// +// @JsonProperty("rdnmadr") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String rdnmadr, +// +// @JsonProperty("lnmadr") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String lnmadr, +// +// @JsonProperty("latitude") +// Double latitude, +// +// @JsonProperty("longitude") +// Double longitude, +// +// @JsonProperty("referenceDate") +// @JsonFormat(pattern = "yyyy-MM-dd") +// LocalDate referenceDate, +// +// @JsonProperty("insttCode") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String insttCode, +// +// @JsonProperty("insttNm") +// @JsonSetter(nulls = Nulls.AS_EMPTY) +// String insttNm +//) { +// public ClutrFatvlInfo { +// latitude = latitude == null ? 0.0 : latitude; +// longitude = longitude == null ? 0.0 : longitude; +// } +// +//} diff --git a/src/main/java/backend/airo/batch/utils/ParsingAreaCode.java b/src/main/java/backend/airo/gerbege/utils/ParsingAreaCode.java similarity index 99% rename from src/main/java/backend/airo/batch/utils/ParsingAreaCode.java rename to src/main/java/backend/airo/gerbege/utils/ParsingAreaCode.java index e109361..18f41ef 100644 --- a/src/main/java/backend/airo/batch/utils/ParsingAreaCode.java +++ b/src/main/java/backend/airo/gerbege/utils/ParsingAreaCode.java @@ -1,4 +1,4 @@ -package backend.airo.batch.utils; +package backend.airo.gerbege.utils; import backend.airo.cache.vo.AreaName; diff --git a/src/main/java/backend/airo/infra/open_api/area_find/adapter/OpenApiAreaCodeAdapter.java b/src/main/java/backend/airo/infra/open_api/area_find/adapter/OpenApiAreaCodeAdapter.java index fb88205..ec8996e 100644 --- a/src/main/java/backend/airo/infra/open_api/area_find/adapter/OpenApiAreaCodeAdapter.java +++ b/src/main/java/backend/airo/infra/open_api/area_find/adapter/OpenApiAreaCodeAdapter.java @@ -25,7 +25,7 @@ public List getCityCode(List megaCodes, Map me List cityList = new ArrayList<>(); for (MegaCode code : megaCodes) { try { - cityList.addAll(openApiAreaFeignClient.getListSigungusBySido("cty", code.ctprvnCd().toString()).items()); + cityList.addAll(openApiAreaFeignClient.getListSigungusBySido("cty", code.getCtprvnCd().toString()).items()); Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(); diff --git a/src/main/java/backend/airo/infra/open_api/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java b/src/main/java/backend/airo/infra/open_api/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java deleted file mode 100644 index 5e47598..0000000 --- a/src/main/java/backend/airo/infra/open_api/clure_fatvl/adapter/OpenApiClureFatvlAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -package backend.airo.infra.open_api.clure_fatvl.adapter; - -import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlInfo; -import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlResponse; -import backend.airo.domain.clure_fatvl.port.ClureFatvlPort; -import backend.airo.infra.open_api.clure_fatvl.client.OpenApiClureFatvlFeignClient; -import backend.airo.infra.open_api.clure_fatvl.dto.OpenApiClureFatvlResponse; -import backend.airo.infra.open_api.clure_fatvl.vo.ClutrFatvlInfo; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class OpenApiClureFatvlAdapter implements ClureFatvlPort { - - private final OpenApiClureFatvlFeignClient openApiClureFatvlFeignClient; - - public OpenApiClutrFatvlResponse getOpenApiClureFatvl(String page, String pageSize, String startDate) { - OpenApiClureFatvlResponse clutrFatvlInfo = openApiClureFatvlFeignClient.getClutrFatvlInfo(page, pageSize, startDate); - return new OpenApiClutrFatvlResponse( - clutrFatvlInfo.body() != null - ? clutrFatvlInfo.items().stream().map(list -> - new OpenApiClutrFatvlInfo( - list.fstvlNm(), - list.opar(), - list.fstvlCo(), - list.fstvlStartDate(), - list.fstvlEndDate(), - list.latitude(), - list.longitude(), - list.rdnmadr(), - list.lnmadr(), - list.mnnstNm(), - list.auspcInsttNm(), - list.suprtInsttNm(), - list.phoneNumber(), - list.homepageUrl(), - list.relateInfo(), - list.referenceDate(), - list.insttCode(), - list.insttNm() - )).toList() - : List.of(), - clutrFatvlInfo.header().resultCode(), - clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().numOfRows() : String.valueOf(0), - clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().pageNo() : String.valueOf(0), - clutrFatvlInfo.body() != null ? clutrFatvlInfo.body().totalCount() : String.valueOf(0) - ); - } -} diff --git a/src/main/java/backend/airo/infra/open_api/clure_fatvl/client/OpenApiClureFatvlFeignClient.java b/src/main/java/backend/airo/infra/open_api/clure_fatvl/client/OpenApiClureFatvlFeignClient.java deleted file mode 100644 index 58c4543..0000000 --- a/src/main/java/backend/airo/infra/open_api/clure_fatvl/client/OpenApiClureFatvlFeignClient.java +++ /dev/null @@ -1,28 +0,0 @@ -package backend.airo.infra.open_api.clure_fatvl.client; - -import backend.airo.infra.open_api.clure_fatvl.dto.OpenApiClureFatvlResponse; -import backend.airo.infra.open_api.clure_fatvl.vo.ClutrFatvlInfo; -import backend.airo.infra.open_api.config.OpenApiFeignClientConfiguration; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; - -/** - * 문화체육관광부에서 제공하는 전국문화축제표준 데이터(Open API)를 이용한 행사, 축제 등 데이터 수집 - * ... - */ -@FeignClient( - name = "openApi-clutr-fstvl", - url = "http://api.data.go.kr/openapi", - configuration = OpenApiFeignClientConfiguration.class) -public interface OpenApiClureFatvlFeignClient { - - @GetMapping("/tn_pubr_public_cltur_fstvl_api") - OpenApiClureFatvlResponse getClutrFatvlInfo( - @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, - @RequestParam(value = "numOfRows", defaultValue = "10000", required = false) String numOfRows, - @RequestParam(value = "fstvlStartDate") String fstvlStartDate -// @RequestParam(value = "fstvlEndDate", required = false) String fstvlEndDate - ); - -} diff --git a/src/main/java/backend/airo/infra/open_api/clure_fatvl/dto/OpenApiClureFatvlResponse.java b/src/main/java/backend/airo/infra/open_api/clure_fatvl/dto/OpenApiClureFatvlResponse.java deleted file mode 100644 index 27122a3..0000000 --- a/src/main/java/backend/airo/infra/open_api/clure_fatvl/dto/OpenApiClureFatvlResponse.java +++ /dev/null @@ -1,49 +0,0 @@ -package backend.airo.infra.open_api.clure_fatvl.dto; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record OpenApiClureFatvlResponse( - @JsonProperty("response") Response response -) { - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Response( - @JsonProperty("header") Header header, - @JsonProperty("body") Body body - ) { - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Header( - @JsonProperty("resultCode") String resultCode, - @JsonProperty("resultMsg") String resultMsg, - @JsonProperty("type") String type // 응답에 있으므로 추가(없어도 무시 가능) - ) { - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public record Body( - @JsonProperty("items") List items, - @JsonProperty("numOfRows") String numOfRows, // JSON이 문자열이므로 String으로 받는 게 안전 - @JsonProperty("pageNo") String pageNo, - @JsonProperty("totalCount") String totalCount - ) { - } - - /** 편의 메서드 */ - public List items() { - return response().body().items(); - } - - public Body body() { - return response().body(); - } - - public Header header() { - return response.header(); - } -} diff --git a/src/main/java/backend/airo/infra/open_api/clure_fatvl/vo/ClutrFatvlInfo.java b/src/main/java/backend/airo/infra/open_api/clure_fatvl/vo/ClutrFatvlInfo.java deleted file mode 100644 index 64a04ee..0000000 --- a/src/main/java/backend/airo/infra/open_api/clure_fatvl/vo/ClutrFatvlInfo.java +++ /dev/null @@ -1,84 +0,0 @@ -package backend.airo.infra.open_api.clure_fatvl.vo; - -import com.fasterxml.jackson.annotation.*; - -import java.time.LocalDate; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record ClutrFatvlInfo( - @JsonProperty("fstvlNm") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String fstvlNm, - - @JsonProperty("opar") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String opar, - - @JsonProperty("fstvlStartDate") - @JsonFormat(pattern = "yyyy-MM-dd") - LocalDate fstvlStartDate, - - @JsonProperty("fstvlEndDate") - @JsonFormat(pattern = "yyyy-MM-dd") - LocalDate fstvlEndDate, - - @JsonProperty("fstvlCo") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String fstvlCo, - - @JsonProperty("mnnstNm") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String mnnstNm, - - @JsonProperty("auspcInsttNm") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String auspcInsttNm, - - @JsonProperty("suprtInsttNm") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String suprtInsttNm, - - @JsonProperty("phoneNumber") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String phoneNumber, - - @JsonProperty("homepageUrl") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String homepageUrl, - - @JsonProperty("relateInfo") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String relateInfo, - - @JsonProperty("rdnmadr") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String rdnmadr, - - @JsonProperty("lnmadr") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String lnmadr, - - @JsonProperty("latitude") - Double latitude, - - @JsonProperty("longitude") - Double longitude, - - @JsonProperty("referenceDate") - @JsonFormat(pattern = "yyyy-MM-dd") - LocalDate referenceDate, - - @JsonProperty("insttCode") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String insttCode, - - @JsonProperty("insttNm") - @JsonSetter(nulls = Nulls.AS_EMPTY) - String insttNm -) { - public ClutrFatvlInfo { - latitude = latitude == null ? 0.0 : latitude; - longitude = longitude == null ? 0.0 : longitude; - } - -} diff --git a/src/main/java/backend/airo/infra/open_api/config/FeignConfig.java b/src/main/java/backend/airo/infra/open_api/config/FeignConfig.java index febd7ec..ed7b898 100644 --- a/src/main/java/backend/airo/infra/open_api/config/FeignConfig.java +++ b/src/main/java/backend/airo/infra/open_api/config/FeignConfig.java @@ -1,12 +1,51 @@ package backend.airo.infra.open_api.config; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.type.LogicalType; +import feign.codec.Decoder; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.Configuration; +import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; +import org.springframework.cloud.openfeign.support.SpringDecoder; +import org.springframework.context.annotation.*; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.beans.factory.ObjectFactory; + @Configuration @EnableFeignClients( - basePackages = "backend.airo.infra.open_api" + basePackages = "backend.airo.infra.open_api", + defaultConfiguration = FeignConfig.FeignJacksonConfig.class ) public class FeignConfig { + @Configuration(proxyBeanMethods = false) + public static class FeignJacksonConfig { + @Bean + public ObjectMapper feignObjectMapper() { + ObjectMapper m = new ObjectMapper(); + m.registerModule(new JavaTimeModule()); + m.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + // 빈 문자열 대응: "" -> null + m.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); + m.coercionConfigFor(LogicalType.POJO) + .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull); + // item이 단일 객체로 올 때 배열로 허용 + m.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + return m; + } + } + + @Bean + public Decoder feignDecoder(ObjectMapper feignObjectMapper) { + var jackson = new MappingJackson2HttpMessageConverter(feignObjectMapper); + ObjectFactory factory = + () -> new HttpMessageConverters(jackson); + return new ResponseEntityDecoder(new SpringDecoder(factory)); + } + } diff --git a/src/main/java/backend/airo/infra/open_api/rural_ex/client/OpenApiRuralExFeignClient.java b/src/main/java/backend/airo/infra/open_api/rural_ex/client/OpenApiRuralExFeignClient.java index 3ed4ed1..50231a9 100644 --- a/src/main/java/backend/airo/infra/open_api/rural_ex/client/OpenApiRuralExFeignClient.java +++ b/src/main/java/backend/airo/infra/open_api/rural_ex/client/OpenApiRuralExFeignClient.java @@ -1,6 +1,6 @@ package backend.airo.infra.open_api.rural_ex.client; -import backend.airo.infra.open_api.config.OpenApiFeignClientConfiguration; +import backend.airo.infra.open_api.rural_ex.config.OpenApiFeignClientConfiguration; import backend.airo.infra.open_api.rural_ex.dto.OpenApiRuralExResponse; import backend.airo.infra.open_api.rural_ex.vo.RuralExInfo; import org.springframework.cloud.openfeign.FeignClient; diff --git a/src/main/java/backend/airo/infra/open_api/config/OpenApiFeignClientConfiguration.java b/src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiFeignClientConfiguration.java similarity index 86% rename from src/main/java/backend/airo/infra/open_api/config/OpenApiFeignClientConfiguration.java rename to src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiFeignClientConfiguration.java index 4175f55..79b8abe 100644 --- a/src/main/java/backend/airo/infra/open_api/config/OpenApiFeignClientConfiguration.java +++ b/src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiFeignClientConfiguration.java @@ -1,4 +1,4 @@ -package backend.airo.infra.open_api.config; +package backend.airo.infra.open_api.rural_ex.config; import feign.Logger; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/backend/airo/infra/open_api/config/OpenApiRequestInterceptor.java b/src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiRequestInterceptor.java similarity index 90% rename from src/main/java/backend/airo/infra/open_api/config/OpenApiRequestInterceptor.java rename to src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiRequestInterceptor.java index 0ce0a48..b264643 100644 --- a/src/main/java/backend/airo/infra/open_api/config/OpenApiRequestInterceptor.java +++ b/src/main/java/backend/airo/infra/open_api/rural_ex/config/OpenApiRequestInterceptor.java @@ -1,4 +1,4 @@ -package backend.airo.infra.open_api.config; +package backend.airo.infra.open_api.rural_ex.config; import feign.RequestInterceptor; import feign.RequestTemplate; diff --git a/src/main/java/backend/airo/infra/open_api/shop/adapter/OpenApiShopAdapter.java b/src/main/java/backend/airo/infra/open_api/shop/adapter/OpenApiShopAdapter.java deleted file mode 100644 index 8a27951..0000000 --- a/src/main/java/backend/airo/infra/open_api/shop/adapter/OpenApiShopAdapter.java +++ /dev/null @@ -1,49 +0,0 @@ -package backend.airo.infra.open_api.shop.adapter; - -import backend.airo.domain.shop.Shop; -import backend.airo.domain.shop.dto.ShopPage; -import backend.airo.domain.shop.port.OpenApiShopPort; -import backend.airo.domain.shop.vo.*; -import backend.airo.infra.open_api.shop.client.OpenApiShopFeignClient; -import backend.airo.infra.open_api.shop.dto.OpenApiShopResponse; -import backend.airo.infra.open_api.shop.vo.ShopInfo; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class OpenApiShopAdapter implements OpenApiShopPort { - - private final OpenApiShopFeignClient openApiShopFeignClient; - - public ShopPage getShopData(String pageNo, String numOfRows, String divId, String key) { - OpenApiShopResponse> openApiShopInfo = openApiShopFeignClient.getShopInfo(pageNo, numOfRows, divId, key); - List shops = openApiShopInfo.getItems().stream() - .filter(info -> isValidShopType(info.indsLclsCd())) - .map(list -> - new Shop( - list.bizesNm(), - new IndustryCodes(list.ksicCd(), list.indsLclsCd(), list.indsMclsCd(), list.indsSclsCd()), - new RegionCodes(list.ctprvnCd(), list.signguCd(), list.adongCd(), list.ldongCd()), - new ShopAddress(list.rdnmAdr(), list.lnoAdr(), list.newZipcd()), - new ShopGeoPoint(list.lat(), list.lon()), - new FloorInfo(list.flrNo(), list.hoNo()), - ShopType.valueOf(list.indsLclsCd()), - list.brchNm() - ) - ).toList(); - OpenApiShopResponse.Body> body = openApiShopInfo.body(); - return new ShopPage(shops, body.numOfRows(), body.pageNo(), body.totalCount()); - } - - private boolean isValidShopType(String code) { - try { - ShopType.valueOf(code); - return true; - } catch (IllegalArgumentException e) { - return false; - } - } -} diff --git a/src/main/java/backend/airo/infra/open_api/tour/adapter/OpenApiTourAdapter.java b/src/main/java/backend/airo/infra/open_api/tour/adapter/OpenApiTourAdapter.java new file mode 100644 index 0000000..b0ee584 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/adapter/OpenApiTourAdapter.java @@ -0,0 +1,106 @@ +package backend.airo.infra.open_api.tour.adapter; + +import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvl; +import backend.airo.application.clure_fatvl.dto.OpenApiClutrFatvlResponse; +import backend.airo.domain.clure_fatvl.port.ClureFatvlPort; +import backend.airo.domain.shop.Shop; +import backend.airo.domain.shop.dto.ShopPage; +import backend.airo.domain.shop.port.OpenApiShopPort; +import backend.airo.domain.shop.vo.*; +import backend.airo.infra.open_api.tour.client.OpenApiKoreaTourFeignClient; +import backend.airo.infra.open_api.tour.dto.OpenApiKoreaTourResponse; +import backend.airo.infra.open_api.tour.vo.KoreaTourFatvl; +import backend.airo.infra.open_api.tour.vo.KoreaTourShoplInfo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class OpenApiTourAdapter implements OpenApiShopPort, ClureFatvlPort { + +// private final OpenApiShopFeignClient openApiShopFeignClient; + private final OpenApiKoreaTourFeignClient openApiKoreaTourFeignClient; + +// public ShopPage getShopData(String pageNo, String numOfRows, String divId, String key) { +// OpenApiShopResponse> openApiShopInfo = openApiShopFeignClient.getShopInfo(pageNo, numOfRows, divId, key); +// List shops = openApiShopInfo.getItems().stream() +// .filter(info -> isValidShopType(info.indsLclsCd())) +// .map(list -> +// new Shop( +// list.bizesNm(), +// new IndustryCodes(list.ksicCd(), list.indsLclsCd(), list.indsMclsCd(), list.indsSclsCd()), +// new RegionCodes(list.ctprvnCd(), list.signguCd(), list.adongCd(), list.ldongCd()), +// new ShopAddress(list.rdnmAdr(), list.lnoAdr(), list.newZipcd()), +// new ShopGeoPoint(list.lat(), list.lon()), +// new FloorInfo(list.flrNo(), list.hoNo()), +// ShopType.valueOf(list.indsLclsCd()), +// list.brchNm() +// ) +// ).toList(); +// OpenApiShopResponse.Body> body = openApiShopInfo.body(); +// return new ShopPage(shops, body.numOfRows(), body.pageNo(), body.totalCount()); +// } + +// private boolean isValidShopType(String code) { +// try { +// ShopType.valueOf(code); +// return true; +// } catch (IllegalArgumentException e) { +// return false; +// } +// } + + + @Override + public ShopPage getShopData(String pageNo, String contentTypeId, String megaCode) { + OpenApiKoreaTourResponse openApiShopInfo = openApiKoreaTourFeignClient.getShopInfo(pageNo, contentTypeId, megaCode); + List shops = openApiShopInfo.item().stream() + .map(list -> + new Shop( + list.contentid(), + list.contenttypeid(), + list.title(), + new IndustryCodes(list.cat1(), list.cat2(), list.cat3()), + new RegionCodes(list.lDongRegnCd(), list.lDongRegnCd() + list.lDongSignguCd()), + new ShopAddress(list.addr1(), list.addr2()), + new ShopGeoPoint(list.mapy(), list.mapx()), + list.firstimage(), + list.firstimage2() + ) + ).toList(); + OpenApiKoreaTourResponse.Body body = openApiShopInfo.body(); + return new ShopPage(shops, body.numOfRows(), body.pageNo(), body.totalCount()); + } + + @Override + public OpenApiClutrFatvlResponse getOpenApiClureFatvl(String page, String contentId, String modifiedtime) { + OpenApiKoreaTourResponse openApiKoreaTourResponse = openApiKoreaTourFeignClient.getClureFatvl(page, contentId, modifiedtime); + return new OpenApiClutrFatvlResponse( + openApiKoreaTourResponse.body().items() != null + ? openApiKoreaTourResponse.item().stream().map(list -> + new OpenApiClutrFatvl( + list.contentId(), + list.contentTypeId(), + list.title(), + list.mapY(), + list.mapX(), + list.addr1(), + list.addr2(), + list.lDongRegnCd(), + list.lDongRegnCd() + list.lDongSignguCd(), + list.tel(), + list.cat1(), + list.firstImage(), + list.firstImage2(), + list.modifiedTime().toLocalDate() + )).toList() + :List.of(), + openApiKoreaTourResponse.header().resultCode(), + openApiKoreaTourResponse.body() != null ? String.valueOf(openApiKoreaTourResponse.body().numOfRows()) : String.valueOf(0), + openApiKoreaTourResponse.body() != null ? String.valueOf(openApiKoreaTourResponse.body().pageNo()) : String.valueOf(0), + openApiKoreaTourResponse.body() != null ? String.valueOf(openApiKoreaTourResponse.body().totalCount()) : String.valueOf(0) + ); + } +} diff --git a/src/main/java/backend/airo/infra/open_api/tour/client/OpenApiKoreaTourFeignClient.java b/src/main/java/backend/airo/infra/open_api/tour/client/OpenApiKoreaTourFeignClient.java new file mode 100644 index 0000000..f527ce1 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/client/OpenApiKoreaTourFeignClient.java @@ -0,0 +1,50 @@ +package backend.airo.infra.open_api.tour.client; + +import backend.airo.infra.open_api.tour.config.OpenApiFeignClientTourConfiguration; +import backend.airo.infra.open_api.tour.dto.OpenApiKoreaTourResponse; +import backend.airo.infra.open_api.tour.vo.KoreaTourFatvl; +import backend.airo.infra.open_api.tour.vo.KoreaTourFatvlInfo; +import backend.airo.infra.open_api.tour.vo.KoreaTourShoplInfo; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 한국관광공사에서 제공하는 관광정보 서비스를 이용한 행사, 축제데이터 수집 + * ... + */ +@FeignClient( + name = "openApi-korea-tour", + url = "https://apis.data.go.kr/B551011", + configuration = OpenApiFeignClientTourConfiguration.class) +public interface OpenApiKoreaTourFeignClient { + + @GetMapping("/KorService2/areaBasedList2") + OpenApiKoreaTourResponse getShopInfo( + @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, + @RequestParam(value = "contentTypeId") String contentId, + @RequestParam(value = "lDongRegnCd") String megaId + ); + + + @GetMapping("/KorService2/areaBasedList2") + OpenApiKoreaTourResponse getClureFatvl( + @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, + @RequestParam(value = "contentTypeId") String contentId, + @RequestParam(value = "modifiedtime") String modifiedtime + ); + + @GetMapping("/KorService2/detailIntro2") + OpenApiKoreaTourResponse getClureFatvlIntro( + @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, + @RequestParam(value = "contentId") String contentId, + @RequestParam(value = "contentTypeId") String contentTypeId + ); + + @GetMapping("/KorService2/detailInfo2") + OpenApiKoreaTourResponse getClureFatvlInfo( + @RequestParam(value = "pageNo", defaultValue = "1", required = false) String pageNo, + @RequestParam(value = "contentId") String contentId, + @RequestParam(value = "contentTypeId") String contentTypeId + ); +} diff --git a/src/main/java/backend/airo/infra/open_api/shop/client/OpenApiShopFeignClient.java b/src/main/java/backend/airo/infra/open_api/tour/client/OpenApiShopFeignClient.java similarity index 85% rename from src/main/java/backend/airo/infra/open_api/shop/client/OpenApiShopFeignClient.java rename to src/main/java/backend/airo/infra/open_api/tour/client/OpenApiShopFeignClient.java index 34fdec0..ad8c3cb 100644 --- a/src/main/java/backend/airo/infra/open_api/shop/client/OpenApiShopFeignClient.java +++ b/src/main/java/backend/airo/infra/open_api/tour/client/OpenApiShopFeignClient.java @@ -1,8 +1,8 @@ -package backend.airo.infra.open_api.shop.client; +package backend.airo.infra.open_api.tour.client; -import backend.airo.infra.open_api.config.OpenApiFeignClientConfiguration; -import backend.airo.infra.open_api.shop.dto.OpenApiShopResponse; -import backend.airo.infra.open_api.shop.vo.ShopInfo; +import backend.airo.infra.open_api.rural_ex.config.OpenApiFeignClientConfiguration; +import backend.airo.infra.open_api.tour.dto.OpenApiShopResponse; +import backend.airo.infra.open_api.tour.vo.ShopInfo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; diff --git a/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiFeignClientTourConfiguration.java b/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiFeignClientTourConfiguration.java new file mode 100644 index 0000000..a26e593 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiFeignClientTourConfiguration.java @@ -0,0 +1,18 @@ +package backend.airo.infra.open_api.tour.config; + +import feign.Logger; +import org.springframework.context.annotation.Bean; + +public class OpenApiFeignClientTourConfiguration { + + @Bean + public OpenApiTourRequestInterceptor openApiTourRequestInterceptor() { + return new OpenApiTourRequestInterceptor(); + } + + @Bean + Logger.Level feignLoggerLevel() { + return Logger.Level.FULL; + } + +} \ No newline at end of file diff --git a/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiTourRequestInterceptor.java b/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiTourRequestInterceptor.java new file mode 100644 index 0000000..b94927b --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/config/OpenApiTourRequestInterceptor.java @@ -0,0 +1,22 @@ +package backend.airo.infra.open_api.tour.config; + +import feign.RequestInterceptor; +import feign.RequestTemplate; +import org.springframework.beans.factory.annotation.Value; + +public class OpenApiTourRequestInterceptor implements RequestInterceptor { + + @Value("${openapi.service.key}") + private String serviceKey; + + @Override + public void apply(RequestTemplate template) { + template.header("Content-type", "application/json"); + template.query("serviceKey", serviceKey); + template.query("_type", "json"); + template.query("MobileOS", "WEB"); + template.query("MobileApp", "AIRO"); + template.query("arrange", "D"); + template.query("numOfRows", "10000"); + } +} \ No newline at end of file diff --git a/src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiKoreaTourResponse.java b/src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiKoreaTourResponse.java new file mode 100644 index 0000000..0ac8b42 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiKoreaTourResponse.java @@ -0,0 +1,60 @@ +package backend.airo.infra.open_api.tour.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record OpenApiKoreaTourResponse( + @JsonProperty("response") Response response +) { + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Response( + @JsonProperty("header") Header header, + @JsonProperty("body") Body body + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Header( + @JsonProperty("resultCode") String resultCode, + @JsonProperty("resultMsg") String resultMsg + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Body( + @JsonProperty("items") Items items, + @JsonProperty("numOfRows") Integer numOfRows, + @JsonProperty("pageNo") Integer pageNo, + @JsonProperty("totalCount") Long totalCount + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Items( + @JsonProperty("item") + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + List item + ) { } + + public Items items() { + return response.body().items; + } + + /** 편의 메서드 */ + public List item() { + return (response == null || response.body() == null) ? List.of() : response.body().items.item; + } + + public Body body() { + return response().body(); + } + + public Header header() { + return response.header(); + } +} diff --git a/src/main/java/backend/airo/infra/open_api/shop/dto/OpenApiShopResponse.java b/src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiShopResponse.java similarity index 95% rename from src/main/java/backend/airo/infra/open_api/shop/dto/OpenApiShopResponse.java rename to src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiShopResponse.java index a86580d..c59c6dc 100644 --- a/src/main/java/backend/airo/infra/open_api/shop/dto/OpenApiShopResponse.java +++ b/src/main/java/backend/airo/infra/open_api/tour/dto/OpenApiShopResponse.java @@ -1,4 +1,4 @@ -package backend.airo.infra.open_api.shop.dto; +package backend.airo.infra.open_api.tour.dto; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvl.java b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvl.java new file mode 100644 index 0000000..cfc9dfe --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvl.java @@ -0,0 +1,39 @@ +package backend.airo.infra.open_api.tour.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.LocalDateTime; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record KoreaTourFatvl( + @JsonProperty("addr1") String addr1, + @JsonProperty("addr2") String addr2, + @JsonProperty("areacode") int areaCode, + @JsonProperty("cat1") String cat1, + @JsonProperty("cat2") String cat2, + @JsonProperty("cat3") String cat3, + @JsonProperty("contentid") long contentId, + @JsonProperty("contenttypeid") int contentTypeId, + @JsonProperty("createdtime") + @JsonFormat(pattern = "yyyyMMddHHmmss") LocalDateTime createdTime, + @JsonProperty("firstimage") String firstImage, + @JsonProperty("firstimage2") String firstImage2, + @JsonProperty("cpyrhtDivCd") String copyrightDivCd, + @JsonProperty("mapx") double mapX, + @JsonProperty("mapy") double mapY, + @JsonProperty("mlevel") int mlevel, + @JsonProperty("modifiedtime") + @JsonFormat(pattern = "yyyyMMddHHmmss") LocalDateTime modifiedTime, + @JsonProperty("sigungucode") int sigunguCode, + @JsonProperty("tel") String tel, + @JsonProperty("title") String title, + @JsonProperty("zipcode") String zipcode, // 유지: 선행 0 보존 + @JsonProperty("lDongRegnCd") int lDongRegnCd, + @JsonProperty("lDongSignguCd") int lDongSignguCd, + @JsonProperty("lclsSystm1") String lclsSystm1, + @JsonProperty("lclsSystm2") String lclsSystm2, + @JsonProperty("lclsSystm3") String lclsSystm3 +) { +} diff --git a/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvlInfo.java b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvlInfo.java new file mode 100644 index 0000000..4128dc1 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourFatvlInfo.java @@ -0,0 +1,43 @@ +package backend.airo.infra.open_api.tour.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record KoreaTourFatvlInfo( + @JsonProperty("contentid") long contentId, + @JsonProperty("contenttypeid") int contentTypeId, + + @JsonProperty("sponsor1") String sponsor1, + @JsonProperty("sponsor1tel") String sponsor1Tel, + @JsonProperty("sponsor2") String sponsor2, + @JsonProperty("sponsor2tel") String sponsor2Tel, + + @JsonProperty("eventstartdate") + @JsonFormat(pattern = "yyyyMMdd") LocalDate eventStartDate, + + @JsonProperty("eventenddate") + @JsonFormat(pattern = "yyyyMMdd") LocalDate eventEndDate, + + @JsonProperty("playtime") String playTime, + @JsonProperty("eventplace") String eventPlace, + @JsonProperty("eventhomepage") String eventHomepage, + @JsonProperty("agelimit") String ageLimit, + @JsonProperty("bookingplace") String bookingPlace, + @JsonProperty("placeinfo") String placeInfo, + @JsonProperty("subevent") String subEvent, + @JsonProperty("program") String program, + + @JsonProperty("usetimefestival") String useTimeFestival, + @JsonProperty("discountinfofestival") String discountInfoFestival, + @JsonProperty("spendtimefestival") String spendTimeFestival, + @JsonProperty("festivalgrade") String festivalGrade, + + @JsonProperty("progresstype") String progressType, + @JsonProperty("festivaltype") String festivalType +) { +} diff --git a/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourShoplInfo.java b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourShoplInfo.java new file mode 100644 index 0000000..5d6a718 --- /dev/null +++ b/src/main/java/backend/airo/infra/open_api/tour/vo/KoreaTourShoplInfo.java @@ -0,0 +1,105 @@ +package backend.airo.infra.open_api.tour.vo; + +import com.fasterxml.jackson.annotation.*; + +import java.time.LocalDateTime; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record KoreaTourShoplInfo( + @JsonProperty("addr1") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String addr1, + + @JsonProperty("addr2") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String addr2, + + @JsonProperty("areacode") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String areacode, + + @JsonProperty("cat1") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String cat1, + + @JsonProperty("cat2") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String cat2, + + @JsonProperty("cat3") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String cat3, + + @JsonProperty("contentid") + long contentid, + + @JsonProperty("contenttypeid") + int contenttypeid, + + @JsonProperty("createdtime") + @JsonFormat(pattern = "yyyyMMddHHmmss") + LocalDateTime createdtime, + + @JsonProperty("firstimage") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String firstimage, + + @JsonProperty("firstimage2") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String firstimage2, + + @JsonProperty("cpyrhtDivCd") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String cpyrhtDivCd, + + @JsonProperty("mapx") + double mapx, + + @JsonProperty("mapy") + double mapy, + + @JsonProperty("mlevel") + int mlevel, + + @JsonProperty("modifiedtime") + @JsonFormat(pattern = "yyyyMMddHHmmss") + LocalDateTime modifiedtime, + + @JsonProperty("sigungucode") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String sigungucode, + + @JsonProperty("tel") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String tel, + + @JsonProperty("title") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String title, + + @JsonProperty("zipcode") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String zipcode, + + @JsonProperty("lDongRegnCd") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String lDongRegnCd, + + @JsonProperty("lDongSignguCd") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String lDongSignguCd, + + @JsonProperty("lclsSystm1") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String lclsSystm1, + + @JsonProperty("lclsSystm2") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String lclsSystm2, + + @JsonProperty("lclsSystm3") + @JsonSetter(nulls = Nulls.AS_EMPTY) + String lclsSystm3 +) { + +} diff --git a/src/main/java/backend/airo/infra/open_api/shop/vo/ShopInfo.java b/src/main/java/backend/airo/infra/open_api/tour/vo/ShopInfo.java similarity index 96% rename from src/main/java/backend/airo/infra/open_api/shop/vo/ShopInfo.java rename to src/main/java/backend/airo/infra/open_api/tour/vo/ShopInfo.java index 7e8dee3..8ca2cbc 100644 --- a/src/main/java/backend/airo/infra/open_api/shop/vo/ShopInfo.java +++ b/src/main/java/backend/airo/infra/open_api/tour/vo/ShopInfo.java @@ -1,4 +1,4 @@ -package backend.airo.infra.open_api.shop.vo; +package backend.airo.infra.open_api.tour.vo; public record ShopInfo( // 식별·기본 정보 diff --git a/src/main/java/backend/airo/persistence/area_code/adapter/MegaCodeAdapter.java b/src/main/java/backend/airo/persistence/area_code/adapter/MegaCodeAdapter.java index 52fa95c..0c1bc94 100644 --- a/src/main/java/backend/airo/persistence/area_code/adapter/MegaCodeAdapter.java +++ b/src/main/java/backend/airo/persistence/area_code/adapter/MegaCodeAdapter.java @@ -4,7 +4,6 @@ import backend.airo.domain.area_code.repository.MegaRepository; import backend.airo.persistence.area_code.entity.MegaCodeEntity; import backend.airo.persistence.area_code.repository.MegaCodeJpaRepository; -import backend.airo.persistence.shop.entity.ShopEntity; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; diff --git a/src/main/java/backend/airo/persistence/area_code/entity/MegaCodeEntity.java b/src/main/java/backend/airo/persistence/area_code/entity/MegaCodeEntity.java index 533cad3..4eb88a3 100644 --- a/src/main/java/backend/airo/persistence/area_code/entity/MegaCodeEntity.java +++ b/src/main/java/backend/airo/persistence/area_code/entity/MegaCodeEntity.java @@ -23,7 +23,7 @@ public MegaCodeEntity(Long ctprvnCd, String ctprvnNm) { } public static MegaCodeEntity toEntity(MegaCode megaCode) { - return new MegaCodeEntity(megaCode.ctprvnCd(), megaCode.ctprvnNm()); + return new MegaCodeEntity(megaCode.getCtprvnCd(), megaCode.getCtprvnNm()); } public static MegaCode toDomain(MegaCodeEntity megaCodeEntity) { diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlAdapter.java b/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlAdapter.java index 3bd54be..2ed37fd 100644 --- a/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlAdapter.java +++ b/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlAdapter.java @@ -24,11 +24,8 @@ public class ClutrFatvlAdapter implements ClutrFatvlRepository { private final ClutrFatvlJpaRepository clutrFatvlJpaRepository; - @Autowired - private EntityManager em; - @Override - public Page findAll(String megaCode, String cityCode, Pageable pageable) { + public Page findAll(Integer megaCode, Integer cityCode, Pageable pageable) { Page clutrFatvlEntities = clutrFatvlJpaRepository.findByAddress_MegaCodeIdAndAddress_CtprvnCodeId(megaCode, cityCode, pageable); if (clutrFatvlEntities.isEmpty()) { return new PageImpl<>(List.of(), pageable, 0); @@ -36,11 +33,6 @@ public Page findAll(String megaCode, String cityCode, Pageable pagea return clutrFatvlEntities.map(ClutrFatvlEntity::toDomain); } - @Override - public void deleteAllByDate(LocalDate start, LocalDate end) { - clutrFatvlJpaRepository.deleteAllByFstvlStartDateBetween(start, end); - } - @Override public Collection saveAll(Collection aggregates) { List clutrFatvlEntities = aggregates.stream().map(ClutrFatvlEntity::toEntity).toList(); diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlInfoAdapter.java b/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlInfoAdapter.java new file mode 100644 index 0000000..0071bcb --- /dev/null +++ b/src/main/java/backend/airo/persistence/clutrfatvl/adapter/ClutrFatvlInfoAdapter.java @@ -0,0 +1,39 @@ +package backend.airo.persistence.clutrfatvl.adapter; + +import backend.airo.domain.clure_fatvl.ClutrFatvlInfo; +import backend.airo.domain.clure_fatvl.repository.ClturFatvlnfoRepository; +import backend.airo.persistence.clutrfatvl.entity.ClutrFatvlEntity; +import backend.airo.persistence.clutrfatvl.entity.ClutrFatvlInfoEntity; +import backend.airo.persistence.clutrfatvl.repository.ClutrFatvlInfoJpaRepository; +import backend.airo.persistence.clutrfatvl.repository.ClutrFatvlJpaRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class ClutrFatvlInfoAdapter implements ClturFatvlnfoRepository { + + private final ClutrFatvlInfoJpaRepository clutrFatvlInfoJpaRepository; + + @Override + public ClutrFatvlInfo save(ClutrFatvlInfo aggregate) { + return null; + } + + @Override + public Collection saveAll(Collection aggregates) { + return List.of(); + } + + @Override + public ClutrFatvlInfo findById(Long contentId) { + ClutrFatvlInfoEntity clutrFatvlInfoEntity = clutrFatvlInfoJpaRepository.findById(contentId).orElseThrow(() -> + new IllegalArgumentException("ClutrFatvlInfo Not Found with id - " + contentId) + ); + return ClutrFatvlInfoEntity.toDomain(clutrFatvlInfoEntity); + } +} diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlEntity.java b/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlEntity.java index 30bbbf8..68560bd 100644 --- a/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlEntity.java +++ b/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlEntity.java @@ -2,14 +2,14 @@ import backend.airo.domain.clure_fatvl.ClutrFatvl; import backend.airo.domain.clure_fatvl.vo.Address; -import backend.airo.domain.clure_fatvl.vo.FestivalPeriod; import backend.airo.domain.clure_fatvl.vo.GeoPoint; -import backend.airo.infra.open_api.clure_fatvl.vo.ClutrFatvlInfo; -import backend.airo.persistence.abstracts.BaseEntity; +import backend.airo.persistence.abstracts.ImmutableEntity; +import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; import java.time.LocalDate; +import java.util.List; import java.util.UUID; @Entity @@ -21,19 +21,14 @@ uniqueConstraints = @UniqueConstraint(name = "uk_clutr_bizkey", columnNames = "biz_key") ) -public class ClutrFatvlEntity extends BaseEntity { +public class ClutrFatvlEntity extends ImmutableEntity { @Id - private String id; + private Long contentId; - private String fstvlNm; + private Integer contenttypeId; - private String opar; - - private String fstvlCo; - - @Embedded - private FestivalPeriod period; + private String title; @Embedded private GeoPoint location; @@ -41,147 +36,72 @@ public class ClutrFatvlEntity extends BaseEntity { @Embedded private Address address; - private String mnnstNm; - - private String auspcInsttNm; - - private String suprtInsttNm; + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "clutr_fatvl_phone", joinColumns = @JoinColumn(name = "content_id")) + @Column(name = "phone_number", length = 32, nullable = false) + @OrderColumn(name = "seq") + private List phoneNumber; - private String phoneNumber; + private String cat1; - private String homepageUrl; + private String firstImage; - private String relateInfo; + private String firstImage2; - private LocalDate referenceDate; - - private String insttCode; - - private String insttNm; - - @Column(name="biz_key", nullable=false, updatable=false, length=64, unique=true) - private String bizKey; + @JsonFormat(pattern = "yyyyMMddHH") + private LocalDate modifiedDate; @Builder - public ClutrFatvlEntity( - String id, String fstvlNm, String opar, String fstvlCo, - FestivalPeriod period, GeoPoint location, Address address, - String mnnstNm, String auspcInsttNm, String suprtInsttNm, - String phoneNumber, String homepageUrl, String relateInfo, - LocalDate referenceDate, String insttCode, String insttNm, - String bizKey) { - this.id = id; - this.fstvlNm = fstvlNm; - this.opar = opar; - this.fstvlCo = fstvlCo; - this.period = period; + public ClutrFatvlEntity(Long contentId, Integer contenttypeId, String title, GeoPoint location, Address address, List phoneNumber, String cat1, String firstImage, String firstImage2, LocalDate modifiedDate) { + this.contentId = contentId; + this.contenttypeId = contenttypeId; + this.title = title; this.location = location; this.address = address; - this.mnnstNm = mnnstNm; - this.auspcInsttNm = auspcInsttNm; - this.suprtInsttNm = suprtInsttNm; this.phoneNumber = phoneNumber; - this.homepageUrl = homepageUrl; - this.relateInfo = relateInfo; - this.referenceDate = referenceDate; - this.insttCode = insttCode; - this.insttNm = insttNm; - this.bizKey = bizKey; + this.cat1 = cat1; + this.firstImage = firstImage; + this.firstImage2 = firstImage2; + this.modifiedDate = modifiedDate; } + public static ClutrFatvlEntity toEntity(ClutrFatvl dto) { return ClutrFatvlEntity.builder() - .id(generateId()) - .fstvlNm(dto.fstvlNm()) - .opar(dto.opar()) - .fstvlCo(dto.fstvlCo()) - .period(new FestivalPeriod(dto.period().start(), dto.period().end())) - .location(new GeoPoint(dto.location().lat(), dto.location().lon())) - .address(new Address(dto.address().road(), dto.address().lot(), dto.address().megaCodeId(), dto.address().ctprvnCodeId())) - .mnnstNm(dto.mnnstNm()) - .auspcInsttNm(dto.auspcInsttNm()) - .suprtInsttNm(dto.suprtInsttNm()) - .phoneNumber(dto.phoneNumber()) - .homepageUrl(dto.homepageUrl()) - .relateInfo(dto.relateInfo()) - .referenceDate(dto.referenceDate()) - .insttCode(dto.insttCode()) - .insttNm(dto.insttNm()) - .bizKey(computeBizKey(dto.fstvlNm(), dto.insttCode(), dto.period())) - .build(); - } - - public static ClutrFatvl toDomain(ClutrFatvlInfo dto, String megaCodeId, String ctprvnCodeId) { - return ClutrFatvl.builder() - .fstvlNm(dto.fstvlNm()) - .opar(dto.opar()) - .fstvlCo(dto.fstvlCo()) - .period(new FestivalPeriod(dto.fstvlStartDate(), dto.fstvlEndDate())) - .location(new GeoPoint(dto.latitude(), dto.longitude())) - .address(new Address(dto.rdnmadr(), dto.lnmadr(), megaCodeId, ctprvnCodeId)) - .mnnstNm(dto.mnnstNm()) - .auspcInsttNm(dto.auspcInsttNm()) - .suprtInsttNm(dto.suprtInsttNm()) - .phoneNumber(dto.phoneNumber()) - .homepageUrl(dto.homepageUrl()) - .relateInfo(dto.relateInfo()) - .referenceDate(dto.referenceDate()) - .insttCode(dto.insttCode()) - .insttNm(dto.insttNm()) + .contentId(dto.getContentId()) + .contenttypeId(dto.getContenttypeId()) + .title(dto.getTitle()) + .location(dto.getLocation()) + .address(dto.getAddress()) + .phoneNumber(dto.getPhoneNumber()) + .cat1(dto.getCat1()) + .firstImage(dto.getFirstImage()) + .firstImage2(dto.getFirstImage2()) + .modifiedDate(dto.getModifiedDate()) .build(); } +// +// public static ClutrFatvl toDomain(ClutrFatvlInfo dto, String megaCodeId, String ctprvnCodeId) { +// return ClutrFatvl.builder() +// .contentId() +// .build(); +// } public static ClutrFatvl toDomain(ClutrFatvlEntity clutrFatvlEntity) { - FestivalPeriod period = clutrFatvlEntity.period; - GeoPoint location = clutrFatvlEntity.location; - Address address = clutrFatvlEntity.address; return ClutrFatvl.builder() - .id(clutrFatvlEntity.id) - .fstvlNm(clutrFatvlEntity.fstvlNm) - .opar(clutrFatvlEntity.opar) - .fstvlCo(clutrFatvlEntity.fstvlCo) - .period(new FestivalPeriod(period.start(), period.end())) - .location(new GeoPoint(location.lat(), location.lon())) - .address(new Address(address.road(), address.lot(), address.megaCodeId(), address.ctprvnCodeId())) - .mnnstNm(clutrFatvlEntity.mnnstNm) - .auspcInsttNm(clutrFatvlEntity.auspcInsttNm) - .suprtInsttNm(clutrFatvlEntity.suprtInsttNm) + .contentId(clutrFatvlEntity.contentId) + .contenttypeId(clutrFatvlEntity.contenttypeId) + .title(clutrFatvlEntity.title) + .location(clutrFatvlEntity.location) + .address(clutrFatvlEntity.address) .phoneNumber(clutrFatvlEntity.phoneNumber) - .homepageUrl(clutrFatvlEntity.homepageUrl) - .relateInfo(clutrFatvlEntity.relateInfo) - .referenceDate(clutrFatvlEntity.referenceDate) - .insttCode(clutrFatvlEntity.insttCode) - .insttNm(clutrFatvlEntity.insttNm) + .cat1(clutrFatvlEntity.cat1) + .firstImage(clutrFatvlEntity.firstImage) + .firstImage2(clutrFatvlEntity.firstImage2) + .modifiedDate(clutrFatvlEntity.modifiedDate) .build(); } - private static String generateId() { - return UUID.randomUUID().toString(); - } - - private static String computeBizKey(String fstvlNm, String insttCode, FestivalPeriod festivalPeriod) { - String normName = normalize(fstvlNm); - String normInst = insttCode == null ? "" : insttCode.trim(); - String parsingStart = festivalPeriod != null && festivalPeriod.start() != null ? festivalPeriod.start().toString() : ""; - return sha256(normName + "|" + parsingStart + "|" + normInst); - } - - private static String normalize(String s) { - if (s == null) return ""; - return java.text.Normalizer.normalize(s, java.text.Normalizer.Form.NFKC) - .toLowerCase().trim() - .replaceAll("\\s+", " "); - } - - private static String sha256(String val) { - try { - var md = java.security.MessageDigest.getInstance("SHA-256"); - byte[] d = md.digest(val.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - StringBuilder sb = new StringBuilder(d.length*2); - for (byte b : d) sb.append(String.format("%02x", b)); - return sb.toString(); - } catch (Exception e) { throw new IllegalStateException(e); } - } } diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlInfoEntity.java b/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlInfoEntity.java new file mode 100644 index 0000000..40848b2 --- /dev/null +++ b/src/main/java/backend/airo/persistence/clutrfatvl/entity/ClutrFatvlInfoEntity.java @@ -0,0 +1,87 @@ +package backend.airo.persistence.clutrfatvl.entity; + +import backend.airo.domain.clure_fatvl.ClutrFatvlInfo; +import backend.airo.domain.clure_fatvl.vo.FestivalPeriod; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.*; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@ToString +public class ClutrFatvlInfoEntity { + + @Id + private String contentid; + + @Embedded + private FestivalPeriod period; + + private String usetimefestival; + private String playTime; + private String start; + private String end; + private String phoneNumber; + private String agelimit; + private String clutrFatvlIntro; + private String mainProgramInfo; + private String guestProgramInfo; + private String eventHomePage; + private String eventPlace; + + + @Builder + public ClutrFatvlInfoEntity(String contentid, FestivalPeriod period, String usetimefestival, String playTime, String start, String end, String phoneNumber, String agelimit, String clutrFatvlIntro, String mainProgramInfo, String guestProgramInfo, String eventHomePage, String eventPlace) { + this.contentid = contentid; + this.period = period; + this.usetimefestival = usetimefestival; + this.playTime = playTime; + this.start = start; + this.end = end; + this.phoneNumber = phoneNumber; + this.agelimit = agelimit; + this.clutrFatvlIntro = clutrFatvlIntro; + this.mainProgramInfo = mainProgramInfo; + this.guestProgramInfo = guestProgramInfo; + this.eventHomePage = eventHomePage; + this.eventPlace = eventPlace; + } + + public static ClutrFatvlInfo toDomain(ClutrFatvlInfoEntity clutrFatvlInfoEntity) { + return ClutrFatvlInfo.builder() + .contentid(clutrFatvlInfoEntity.contentid) + .playTime(clutrFatvlInfoEntity.playTime) + .start(clutrFatvlInfoEntity.start) + .end(clutrFatvlInfoEntity.end) + .phoneNumber(clutrFatvlInfoEntity.phoneNumber) + .agelimit(clutrFatvlInfoEntity.agelimit) + .clutrFatvlIntro(clutrFatvlInfoEntity.clutrFatvlIntro) + .mainProgramInfo(clutrFatvlInfoEntity.mainProgramInfo) + .guestProgramInfo(clutrFatvlInfoEntity.guestProgramInfo) + .eventHomePage(clutrFatvlInfoEntity.eventHomePage) + .eventPlace(clutrFatvlInfoEntity.eventPlace) + .build(); + } + + public static ClutrFatvlInfoEntity toEntity(ClutrFatvlInfo clutrFatvlInfo) { + return ClutrFatvlInfoEntity.builder() + .contentid(clutrFatvlInfo.getContentid()) + .playTime(clutrFatvlInfo.getPlayTime()) + .start(clutrFatvlInfo.getStart()) + .end(clutrFatvlInfo.getEnd()) + .phoneNumber(clutrFatvlInfo.getPhoneNumber()) + .agelimit(clutrFatvlInfo.getAgelimit()) + .clutrFatvlIntro(clutrFatvlInfo.getClutrFatvlIntro()) + .mainProgramInfo(clutrFatvlInfo.getMainProgramInfo()) + .guestProgramInfo(clutrFatvlInfo.getGuestProgramInfo()) + .eventHomePage(clutrFatvlInfo.getEventHomePage()) + .eventPlace(clutrFatvlInfo.getEventPlace()) + .build(); + } + + + +} + diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlBulkRepository.java b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlBulkRepository.java index 64d8a77..e6665a5 100644 --- a/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlBulkRepository.java +++ b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlBulkRepository.java @@ -2,7 +2,9 @@ import backend.airo.domain.clure_fatvl.ClutrFatvl; import backend.airo.domain.clure_fatvl.repository.ClutrFatvlBulkRepositoryPort; +import backend.airo.domain.clure_fatvl.vo.ClutrFatvlPhoneNumber; import backend.airo.persistence.clutrfatvl.entity.ClutrFatvlEntity; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -12,6 +14,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -25,63 +28,105 @@ public class ClutrFatvlBulkRepository implements ClutrFatvlBulkRepositoryPort { @Override public void batchInsert(List items) { List clutrFatvlEntities = items.stream().map(ClutrFatvlEntity::toEntity).toList(); - int[] results = jdbcTemplate.batchUpdate(makeBulkSql(), new BatchPreparedStatementSetter() { + int[] results = jdbcTemplate.batchUpdate(makeClutrFatvlBulkSql(), new BatchPreparedStatementSetter() { @Override public void setValues(@NotNull PreparedStatement ps, int i) throws SQLException { ClutrFatvlEntity item = clutrFatvlEntities.get(i); - ps.setString(1, item.getBizKey()); - ps.setString(2, item.getId()); - ps.setString(3, item.getFstvlNm()); - ps.setString(4, item.getOpar()); - ps.setString(5, item.getFstvlCo()); - ps.setObject(6, item.getPeriod().start()); - ps.setObject(7, item.getPeriod().end()); - ps.setDouble(8, item.getLocation().lat()); - ps.setDouble(9, item.getLocation().lon()); - ps.setString(10, item.getAddress().road()); - ps.setString(11, item.getAddress().lot()); - ps.setString(12, item.getAddress().megaCodeId()); - ps.setString(13, item.getAddress().ctprvnCodeId()); - ps.setString(14, item.getMnnstNm()); - ps.setString(15, item.getAuspcInsttNm()); - ps.setString(16, item.getSuprtInsttNm()); - ps.setString(17, item.getPhoneNumber()); - ps.setString(18, item.getHomepageUrl()); - ps.setString(19, item.getRelateInfo()); - ps.setObject(20, item.getReferenceDate()); - ps.setString(21, item.getInsttCode()); - ps.setString(22, item.getInsttNm()); - ps.setObject(23, java.time.LocalDateTime.now()); - ps.setObject(24, java.time.LocalDateTime.now()); + ps.setString(1, String.valueOf(item.getContentId())); + ps.setString(2, String.valueOf(item.getContenttypeId())); + ps.setString(3, item.getTitle()); + ps.setString(4, String.valueOf(item.getLocation().lat())); + ps.setString(5, String.valueOf(item.getLocation().lon())); + ps.setObject(6, item.getAddress().addr1()); + ps.setObject(7, item.getAddress().addr2()); + ps.setDouble(8, item.getAddress().megaCodeId()); + ps.setDouble(9, item.getAddress().ctprvnCodeId()); + ps.setString(10, item.getCat1()); + ps.setString(11, item.getFirstImage()); + ps.setString(12, item.getFirstImage2()); + ps.setString(13, String.valueOf(item.getModifiedDate())); } @Override public int getBatchSize() { return items.size(); } + + }); int totalInserted = Arrays.stream(results).sum(); log.info("[batchInsert] batch size: {}, inserted count: {}", clutrFatvlEntities.size(), totalInserted); + + List clutrFatvlPhoneNumbers = new ArrayList<>(); + + for (ClutrFatvlEntity clutrFatvlEntity : clutrFatvlEntities) { + List phoneNumbers = clutrFatvlEntity.getPhoneNumber(); + for (int i = 1; i <= phoneNumbers.size(); i++) { + clutrFatvlPhoneNumbers.add(new ClutrFatvlPhoneNumber(clutrFatvlEntity.getContentId(), i, phoneNumbers.get(i-1))); + } + } + + if (!clutrFatvlPhoneNumbers.isEmpty()) { + jdbcTemplate.batchUpdate(makeClutrFatvlPhoneBulkSql(), new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ClutrFatvlPhoneNumber r = clutrFatvlPhoneNumbers.get(i); + ps.setLong(1, r.contentId()); + ps.setInt(2, r.seq()); + ps.setString(3, r.phoneNumber()); + } + @Override + public int getBatchSize() { + return clutrFatvlPhoneNumbers.size(); + } + } + ); + } + } + + + private static String makeClutrFatvlBulkSql() { + return """ + INSERT INTO clutr_fatvl ( + content_id, + contenttype_id, + title, + latitude, + longitude, + addr1, + addr2, + mega_code_id, + ctprvn_code_id, + cat1, + first_image, + first_image2, + modified_date + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + title = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(title), title), + latitude = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(latitude), latitude), + longitude = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(longitude), longitude), + addr1 = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(addr1), addr1), + addr2 = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(addr2), addr2), + mega_code_id = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(mega_code_id), mega_code_id), + ctprvn_code_id = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(ctprvn_code_id), ctprvn_code_id), + cat1 = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(cat1), cat1), + first_image = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(first_image), first_image), + first_image2 = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(first_image2), first_image2), + modified_date = IF(VALUES(modified_date) > modified_date OR modified_date IS NULL, VALUES(modified_date), modified_date); + """; } - private static String makeBulkSql() { + private static String makeClutrFatvlPhoneBulkSql() { return """ - INSERT INTO clutr_fatvl ( - biz_key, - id, fstvl_nm, opar, fstvl_co, - start_date, end_date, - latitude, longitude, - road_addr, lot_addr, - mega_code_id, ctprvn_code_id, - mnnst_nm, auspc_instt_nm, suprt_instt_nm, - phone_number, homepage_url, relate_info, - reference_date, instt_code, instt_nm, - created_at, updated_at - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - updated_at = CURRENT_TIMESTAMP - """; + INSERT INTO clutr_fatvl_phone ( + content_id, + seq, + phone_number + ) VALUES (?, ?, ?) + ON DUPLICATE KEY UPDATE phone_number = VALUES(phone_number) + """; } } diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlInfoJpaRepository.java b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlInfoJpaRepository.java new file mode 100644 index 0000000..55df850 --- /dev/null +++ b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlInfoJpaRepository.java @@ -0,0 +1,9 @@ +package backend.airo.persistence.clutrfatvl.repository; + +import backend.airo.persistence.clutrfatvl.entity.ClutrFatvlInfoEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClutrFatvlInfoJpaRepository extends JpaRepository { +} diff --git a/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlJpaRepository.java b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlJpaRepository.java index 49ebbe5..6442614 100644 --- a/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlJpaRepository.java +++ b/src/main/java/backend/airo/persistence/clutrfatvl/repository/ClutrFatvlJpaRepository.java @@ -1,20 +1,25 @@ package backend.airo.persistence.clutrfatvl.repository; import backend.airo.persistence.clutrfatvl.entity.ClutrFatvlEntity; +import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.time.LocalDate; +import java.util.Optional; + public interface ClutrFatvlJpaRepository extends JpaRepository { - Page findByAddress_MegaCodeIdAndAddress_CtprvnCodeId(String regionCtprvnCd, String regionSignguCd, Pageable pageable); + Page findByAddress_MegaCodeIdAndAddress_CtprvnCodeId(Integer address_megaCodeId, Integer address_ctprvnCodeId, Pageable pageable); - @Modifying - @Query("DELETE FROM ClutrFatvlEntity f WHERE f.period.start BETWEEN :start AND :end") - void deleteAllByFstvlStartDateBetween(@Param("start") LocalDate start, @Param("end") LocalDate end); + @NotNull + @Override + @EntityGraph(attributePaths = "phoneNumber") + Optional findById(@NotNull Long id); } diff --git a/src/main/java/backend/airo/persistence/shop/entity/ShopEntity.java b/src/main/java/backend/airo/persistence/shop/entity/ShopEntity.java index a621d62..d88e982 100644 --- a/src/main/java/backend/airo/persistence/shop/entity/ShopEntity.java +++ b/src/main/java/backend/airo/persistence/shop/entity/ShopEntity.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @Entity -@Table(name = "shop_entity", +@Table(name = "shop", indexes = { @Index(name = "idx_shop_region", columnList = "ctprvn_cd, signgu_cd"), @Index( @@ -21,8 +21,10 @@ @Getter public class ShopEntity extends BaseEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + private Long contentId; + + private Integer contentTypeId; @Column(name = "shopName", length = 200, nullable = false) private String shopName; @@ -43,51 +45,48 @@ public class ShopEntity extends BaseEntity { @Embedded private ShopGeoPoint location; - //세부 주소[ 지점, 층, 호 ] - @Embedded - private FloorInfo floorInfo; + private String representativeImageURL; - @Enumerated(EnumType.STRING) - private ShopType shopType; + private String thumbnailImageURl; - @Column(name = "brch_nm") - private String brchNm; - public ShopEntity(String shopName, IndustryCodes industry, RegionCodes region, ShopAddress address, ShopGeoPoint location, FloorInfo floorInfo, ShopType shopType, String brchNm) { + public ShopEntity(Long contentId, Integer contentTypeId, String shopName, IndustryCodes industry, RegionCodes region, ShopAddress address, ShopGeoPoint location, String representativeImageURL, String thumbnailImageURl) { + this.contentId = contentId; + this.contentTypeId = contentTypeId; this.shopName = shopName; this.industry = industry; this.region = region; this.address = address; this.location = location; - this.floorInfo = floorInfo; - this.shopType = shopType; - this.brchNm = brchNm; + this.representativeImageURL = representativeImageURL; + this.thumbnailImageURl = thumbnailImageURl; } public static ShopEntity toEntity(Shop shop) { return new ShopEntity( + shop.contentId(), + shop.contentTypeId(), shop.shopName(), shop.industry(), shop.region(), shop.address(), shop.location(), - shop.floorInfo(), - shop.shopType(), - shop.brchNm() + shop.representativeImageURL(), + shop.thumbnailImageURl() ); } public static Shop toDomain(ShopEntity shopEntity) { return new Shop( - shopEntity.id, + shopEntity.contentId, + shopEntity.contentTypeId, shopEntity.shopName, shopEntity.industry, shopEntity.region, shopEntity.address, shopEntity.location, - shopEntity.floorInfo, - shopEntity.shopType, - shopEntity.brchNm + shopEntity.getRepresentativeImageURL(), + shopEntity.getThumbnailImageURl() ); } } diff --git a/src/main/java/backend/airo/worker/schedule/area_code/AreaCodeService.java b/src/main/java/backend/airo/worker/schedule/area_code/AreaCodeService.java index 36bc4f2..c660801 100644 --- a/src/main/java/backend/airo/worker/schedule/area_code/AreaCodeService.java +++ b/src/main/java/backend/airo/worker/schedule/area_code/AreaCodeService.java @@ -32,7 +32,7 @@ public void collectCodeOf() { // 2. 이름 기준으로 MegaCode ID 매핑 Map megaCodeIdMap = handle.stream() - .collect(Collectors.toMap(MegaCode::ctprvnNm, MegaCode::ctprvnCd)); + .collect(Collectors.toMap(MegaCode::getCtprvnNm, MegaCode::getCtprvnCd)); // 3. 시군구 코드 수집 및 MegaCode ID 할당 List codeCodes = areaCodePort.getCityCode(megaCodes,megaCodeIdMap); diff --git a/src/main/java/backend/airo/worker/schedule/shop/ShopDataCollector.java b/src/main/java/backend/airo/worker/schedule/shop/ShopDataCollector.java index 37178f6..c7e9ab7 100644 --- a/src/main/java/backend/airo/worker/schedule/shop/ShopDataCollector.java +++ b/src/main/java/backend/airo/worker/schedule/shop/ShopDataCollector.java @@ -4,6 +4,7 @@ import backend.airo.domain.shop.command.CreateAllShopCommand; import backend.airo.domain.shop.dto.ShopPage; import backend.airo.domain.shop.port.OpenApiShopPort; +import backend.airo.worker.schedule.shop.vo.ContentTypeId; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @@ -17,25 +18,25 @@ public class ShopDataCollector { @Async("apiTaskExecutor") public void processRegion(MegaCode megaCode) { - int pageNo = 1; - boolean hasNext = true; + for (ContentTypeId value : ContentTypeId.values()) { + boolean hasNext = true; + int pageNo = 1; + while (hasNext) { + ShopPage shopPage = openApiShopPort.getShopData( + String.valueOf(pageNo), + value.getTypeId(), + String.valueOf(megaCode.getCtprvnCd()) + ); - while (hasNext) { - ShopPage shopPage = openApiShopPort.getShopData( - String.valueOf(pageNo), - "10000", - "ctprvnCd", - String.valueOf(megaCode.ctprvnCd()) - ); + if (shopPage.items().isEmpty()) break; - if (shopPage.items().isEmpty()) break; + createAllShopCommand.handle(shopPage.items()); - createAllShopCommand.handle(shopPage.items()); + int totalPages = (int) Math.ceil((double) shopPage.totalCount() / shopPage.numOfRows()); + pageNo++; - int totalPages = (int) Math.ceil((double) shopPage.totalCount() / shopPage.numOfRows()); - pageNo++; - - hasNext = pageNo <= totalPages; + hasNext = pageNo <= totalPages; + } } } } diff --git a/src/main/java/backend/airo/worker/schedule/shop/vo/ContentTypeId.java b/src/main/java/backend/airo/worker/schedule/shop/vo/ContentTypeId.java new file mode 100644 index 0000000..52bb2a8 --- /dev/null +++ b/src/main/java/backend/airo/worker/schedule/shop/vo/ContentTypeId.java @@ -0,0 +1,16 @@ +package backend.airo.worker.schedule.shop.vo; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum ContentTypeId { + + FOOD("39"), + IODGMENT("32") + ; + + private final String typeId; + +} diff --git a/src/test/java/backend/airo/AiroApplicationTests.java b/src/test/java/backend/airo/AiroApplicationTests.java index c5cd0c8..c764131 100644 --- a/src/test/java/backend/airo/AiroApplicationTests.java +++ b/src/test/java/backend/airo/AiroApplicationTests.java @@ -5,7 +5,7 @@ import backend.airo.infra.open_api.area_find.client.OpenApiAreaFeignClient; import backend.airo.infra.open_api.clure_fatvl.client.OpenApiClureFatvlFeignClient; import backend.airo.infra.open_api.rural_ex.client.OpenApiRuralExFeignClient; -import backend.airo.infra.open_api.shop.client.OpenApiShopFeignClient; +import backend.airo.infra.open_api.tour.client.OpenApiShopFeignClient; import backend.airo.security.config.FirebaseConfig; import backend.airo.support.notification.ServerStartupNotifier; import net.dv8tion.jda.api.JDA;