From 79889b85adc11912d1794a29e5bc3997a1d32324 Mon Sep 17 00:00:00 2001 From: DebbieIsFree Date: Mon, 20 May 2024 16:17:47 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(#23)=20:=20=ED=95=AD=EA=B3=B5=EA=B6=8C?= =?UTF-8?q?=20domain=20=EC=84=A4=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EnjoyTripBackend/domain/Airplane.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/domain/Airplane.java diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/domain/Airplane.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/domain/Airplane.java new file mode 100644 index 0000000..e65ccbe --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/domain/Airplane.java @@ -0,0 +1,20 @@ +package com.example.EnjoyTripBackend.domain; + +import lombok.*; + +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class Airplane { + private Long id; + private String airlineNm; + private String arrAirportNm; + private String depAirportNm; + private String arrPlandTime; + private String depPlandTime; + private String economyCharge; + private String prestigeCharge; + private String vihicleId; + +} From a1dc37aa69cf4538c28f3c3b17e1ee63d4b040e1 Mon Sep 17 00:00:00 2001 From: DebbieIsFree Date: Mon, 20 May 2024 16:19:01 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat(#23)=20:=20=ED=95=AD=EA=B3=B5=EA=B6=8C?= =?UTF-8?q?=20=EC=99=B8=EB=B6=80=20API=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20db?= =?UTF-8?q?=EC=97=90=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/AirplaneInfoCollector.java | 108 ++++++++++++++++++ .../EnjoyTripBackend/util/DataUpdater.java | 22 ++++ 2 files changed, 130 insertions(+) create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/AirplaneInfoCollector.java create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/DataUpdater.java diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/AirplaneInfoCollector.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/AirplaneInfoCollector.java new file mode 100644 index 0000000..c403e05 --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/AirplaneInfoCollector.java @@ -0,0 +1,108 @@ +package com.example.EnjoyTripBackend.util; + +import com.example.EnjoyTripBackend.domain.Airplane; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneResponseDto; +import com.example.EnjoyTripBackend.exception.EnjoyTripException; +import com.example.EnjoyTripBackend.exception.ErrorCode; +import com.example.EnjoyTripBackend.service.AirplaneService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class AirplaneInfoCollector { + + @Value("${flight.service.key}") + private String serviceKey; + + private final AirplaneService airplaneService; + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + @Scheduled(cron = "0 48 19 * * *") // 매일 오후 7시 48분에 실행 + public void fetchFlightInfo() { + LocalDate today = LocalDate.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + + List depAirportIds = List.of("NAARKJB", "NAARKJJ", "NAARKJK", "NAARKJY", "NAARKNW", "NAARKNY", "NAARKPC", "NAARKPK", "NAARKPS", "NAARKPU", "NAARKSI", "NAARKSS", "NAARKTH", "NAARKTN", "NAARKTU"); + List arrAirportIds = List.of("NAARKJB", "NAARKJJ", "NAARKJK", "NAARKJY", "NAARKNW", "NAARKNY", "NAARKPC", "NAARKPK", "NAARKPS", "NAARKPU", "NAARKSI", "NAARKSS", "NAARKTH", "NAARKTN", "NAARKTU"); + List airlineIds = List.of("AAR", "ABL", "ASV", "ESR", "FGW", "HGG", "JJA", "JNA", "KAL", "TWB"); + + for (int i = 0; i < 31; i++) { // Collect data for 31 days + LocalDate date = today.plusDays(i); + String depPlandTime = date.format(formatter); + + for (String depAirportId : depAirportIds) { + for (String arrAirportId : arrAirportIds) { + if (!depAirportId.equals(arrAirportId)) { // Ensure departure and arrival airports are different + for (String airlineId : airlineIds) { + fetchAndSaveFlightsForDate(depAirportId, arrAirportId, depPlandTime, airlineId); + } + } + } + } + } + } + + private void fetchAndSaveFlightsForDate(String depAirportId, String arrAirportId, String depPlandTime, String airlineId) { + String url = String.format("http://apis.data.go.kr/1613000/DmstcFlightNvgInfoService/getFlightOpratInfoList?serviceKey=%s&_type=json&depAirportId=%s&arrAirportId=%s&depPlandTime=%s&airlineId=%s", + serviceKey, depAirportId, arrAirportId, depPlandTime, airlineId); + + ResponseEntity responseEntity = restTemplate.getForEntity(url, String.class); + + if (responseEntity.getStatusCode().is2xxSuccessful()) { + String responseBody = responseEntity.getBody(); + + try { + JsonNode rootNode = objectMapper.readTree(responseBody); + JsonNode itemsNode = rootNode.path("response").path("body").path("items").path("item"); + + if (itemsNode.isArray()) { + for (JsonNode itemNode : itemsNode) { + String airlineNm = getSafeText(itemNode, "airlineNm"); + String arrAirportNm = getSafeText(itemNode, "arrAirportNm"); + String depAirportNm = getSafeText(itemNode, "depAirportNm"); + String depPlandTimeStr = getSafeText(itemNode, "depPlandTime"); + String arrPlandTimeStr = getSafeText(itemNode, "arrPlandTime"); + String economyCharge = getSafeText(itemNode, "economyCharge"); + String prestigeCharge = getSafeText(itemNode, "prestigeCharge"); + String vihicleId = getSafeText(itemNode, "vihicleId"); + + if (arrAirportNm != null && depAirportNm != null && !arrAirportNm.equals(depAirportNm)) { + AirplaneResponseDto airplaneDto = new AirplaneResponseDto(); + airplaneDto.setAirlineNm(airlineNm); + airplaneDto.setArrAirportNm(arrAirportNm); + airplaneDto.setDepAirportNm(depAirportNm); + airplaneDto.setDepPlandTime(depPlandTimeStr); + airplaneDto.setArrPlandTime(arrPlandTimeStr); + airplaneDto.setEconomyCharge(economyCharge); + airplaneDto.setPrestigeCharge(prestigeCharge); + airplaneDto.setVihicleId(vihicleId); + + airplaneService.save(airplaneDto); + } + } + } + } catch (Exception e) { + throw new EnjoyTripException(ErrorCode.FAIL_INSERT_AIRPLANE_DATA, e.getMessage()); + } + } else { + throw new EnjoyTripException(ErrorCode.FAIL_INSERT_AIRPLANE_DATA, "Failed to fetch airplane data from the API"); + } + } + + private String getSafeText(JsonNode node, String key) { + JsonNode valueNode = node.get(key); + return valueNode != null ? valueNode.asText() : null; + } +} diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/DataUpdater.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/DataUpdater.java new file mode 100644 index 0000000..e526b88 --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/util/DataUpdater.java @@ -0,0 +1,22 @@ +package com.example.EnjoyTripBackend.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class DataUpdater implements CommandLineRunner { + + private final AirplaneInfoCollector airplaneInfoCollector; + + @Autowired + public DataUpdater(AirplaneInfoCollector airplaneInfoCollector) { + this.airplaneInfoCollector = airplaneInfoCollector; + } + + @Override + public void run(String... args) throws Exception { + // 애플리케이션이 시작될 때 실행되는 코드 +// airplaneInfoCollector.fetchFlightInfo(); + } +} From 25ebc0df04cf2c01067e1b79a720c50905b73fea Mon Sep 17 00:00:00 2001 From: DebbieIsFree Date: Mon, 20 May 2024 16:22:46 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat(#23)=20:=20=ED=95=AD=EA=B3=B5=EA=B6=8C?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=96=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?/=EC=9A=94=EC=B2=AD=20dto=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AirplaneController.java | 39 ++++++++++ .../dto/airplane/AirplaneRequestDto.java | 15 ++++ .../dto/airplane/AirplaneResponseDto.java | 20 ++++++ .../repository/AirplaneRepository.java | 18 +++++ .../service/AirplaneService.java | 72 +++++++++++++++++++ .../main/resources/config/mybatis-config.xml | 1 + .../main/resources/mapper/airplane-query.xml | 43 +++++++++++ 7 files changed, 208 insertions(+) create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/controller/AirplaneController.java create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneRequestDto.java create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneResponseDto.java create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/repository/AirplaneRepository.java create mode 100644 EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/service/AirplaneService.java create mode 100644 EnjoyTripBackend/src/main/resources/mapper/airplane-query.xml diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/controller/AirplaneController.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/controller/AirplaneController.java new file mode 100644 index 0000000..34a86f8 --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/controller/AirplaneController.java @@ -0,0 +1,39 @@ +package com.example.EnjoyTripBackend.controller; + +import com.example.EnjoyTripBackend.dto.NonPagingResponseResult; +import com.example.EnjoyTripBackend.dto.ResponseResult; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneRequestDto; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneResponseDto; +import com.example.EnjoyTripBackend.service.AirplaneService; +import com.example.EnjoyTripBackend.util.LimitedSizePagination; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class AirplaneController { + + private final AirplaneService airplaneService; + + @GetMapping("/airplanes") + public ResponseEntity>> airplaneList(@PageableDefault(size = 20) Pageable pageable){ + return ResponseEntity.ok().body(airplaneService.airplaneList(pageable)); + } + + @GetMapping("/airplanes/{id}") + public ResponseEntity> airplaneDetail(@PathVariable("id")Long id){ + return ResponseEntity.ok().body(airplaneService.findById(id)); + } + + @PostMapping("/airplanes/search") + @LimitedSizePagination(maxSize = 20) + public ResponseEntity>> airplaneSearchList(@PageableDefault(size = 20) Pageable pageable, @RequestBody AirplaneRequestDto requestDto){ + return ResponseEntity.ok().body(airplaneService.airplaneSearchList(pageable, requestDto)); + } +} \ No newline at end of file diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneRequestDto.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneRequestDto.java new file mode 100644 index 0000000..fb1bbba --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneRequestDto.java @@ -0,0 +1,15 @@ +package com.example.EnjoyTripBackend.dto.airplane; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class AirplaneRequestDto { + private String depAirportNm; + private String arrAirportNm; + private String depPlandTime; + private String airlineNm; +} diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneResponseDto.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneResponseDto.java new file mode 100644 index 0000000..3c5f42a --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/dto/airplane/AirplaneResponseDto.java @@ -0,0 +1,20 @@ +package com.example.EnjoyTripBackend.dto.airplane; + +import lombok.*; + +@Setter +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AirplaneResponseDto { + private Long id; + private String airlineNm; + private String arrAirportNm; + private String depAirportNm; + private String arrPlandTime; + private String depPlandTime; + private String economyCharge; + private String prestigeCharge; + private String vihicleId; +} diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/repository/AirplaneRepository.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/repository/AirplaneRepository.java new file mode 100644 index 0000000..fc41452 --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/repository/AirplaneRepository.java @@ -0,0 +1,18 @@ +package com.example.EnjoyTripBackend.repository; + +import com.example.EnjoyTripBackend.domain.Airplane; +import com.example.EnjoyTripBackend.dto.PageRequestList; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneResponseDto; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Optional; + +@Mapper +public interface AirplaneRepository { + Long save(Airplane airplane); + List findAll(PageRequestList requestList); + Optional findById(Long id); + List findAllBySearch(PageRequestList requestList); + Long findTotalCount(); +} \ No newline at end of file diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/service/AirplaneService.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/service/AirplaneService.java new file mode 100644 index 0000000..3b034f2 --- /dev/null +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/service/AirplaneService.java @@ -0,0 +1,72 @@ +package com.example.EnjoyTripBackend.service; + +import com.example.EnjoyTripBackend.domain.Airplane; +import com.example.EnjoyTripBackend.dto.NonPagingResponseResult; +import com.example.EnjoyTripBackend.dto.PageRequestList; +import com.example.EnjoyTripBackend.dto.ResponseResult; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneRequestDto; +import com.example.EnjoyTripBackend.dto.airplane.AirplaneResponseDto; +import com.example.EnjoyTripBackend.dto.golf.GolfRequestDto; +import com.example.EnjoyTripBackend.dto.golf.GolfResponseDto; +import com.example.EnjoyTripBackend.dto.place.PlaceResponseDto; +import com.example.EnjoyTripBackend.exception.EnjoyTripException; +import com.example.EnjoyTripBackend.exception.ErrorCode; +import com.example.EnjoyTripBackend.repository.AirplaneRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Date; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Transactional +public class AirplaneService { + + private final AirplaneRepository airplaneRepository; + + @Transactional + public void save(AirplaneResponseDto airplaneResponseDto) { + Airplane airplane = Airplane.builder() + .airlineNm(airplaneResponseDto.getAirlineNm()) + .arrAirportNm(airplaneResponseDto.getArrAirportNm()) + .depAirportNm(airplaneResponseDto.getDepAirportNm()) + .arrPlandTime(airplaneResponseDto.getArrPlandTime()) + .depPlandTime(airplaneResponseDto.getDepPlandTime()) + .economyCharge(airplaneResponseDto.getEconomyCharge()) + .prestigeCharge(airplaneResponseDto.getPrestigeCharge()) + .vihicleId(airplaneResponseDto.getVihicleId()) + .build(); + + airplaneRepository.save(airplane); + } + + public ResponseResult> airplaneList(Pageable pageable) { + PageRequestList requestList = PageRequestList.builder() + .pageable(pageable) + .build(); + + long totalCount = airplaneRepository.findTotalCount(); + int totalPages = (int) Math.ceil((double) totalCount / pageable.getPageSize()); + + return ResponseResult.of("항공권 정보 게시글 목록입니다.", airplaneRepository.findAll(requestList),totalPages); + } + + public NonPagingResponseResult findById(Long id) { + return NonPagingResponseResult.of("항공권 상세 정보 게시글 입니다.", airplaneRepository.findById(id).orElseThrow(() -> new EnjoyTripException(ErrorCode.CONTENT_NOT_FOUNT))); + } + + public ResponseResult> airplaneSearchList(Pageable pageable, AirplaneRequestDto airplaneRequestDto) { + PageRequestList requestList = PageRequestList.builder() + .pageable(pageable) + .data(airplaneRequestDto) + .build(); + List airplanes = airplaneRepository.findAllBySearch(requestList); + long totalCount = airplanes.size(); + int totalPages = (int) Math.ceil((double) totalCount / pageable.getPageSize()); + return ResponseResult.of("검색어 기반 항공권 정보 게시글 목록입니다.", airplanes, totalPages); + } +} diff --git a/EnjoyTripBackend/src/main/resources/config/mybatis-config.xml b/EnjoyTripBackend/src/main/resources/config/mybatis-config.xml index f4b1f03..4c5ae3a 100644 --- a/EnjoyTripBackend/src/main/resources/config/mybatis-config.xml +++ b/EnjoyTripBackend/src/main/resources/config/mybatis-config.xml @@ -13,5 +13,6 @@ + \ No newline at end of file diff --git a/EnjoyTripBackend/src/main/resources/mapper/airplane-query.xml b/EnjoyTripBackend/src/main/resources/mapper/airplane-query.xml new file mode 100644 index 0000000..51a3132 --- /dev/null +++ b/EnjoyTripBackend/src/main/resources/mapper/airplane-query.xml @@ -0,0 +1,43 @@ + + + + + + + INSERT + INTO airplane (airlineNm, arrAirportNm, depAirportNm, arrPlandTime, depPlandTime, economyCharge, prestigeCharge, vihicleId) + VALUES (#{airlineNm}, #{arrAirportNm}, #{depAirportNm}, #{arrPlandTime}, #{depPlandTime}, #{economyCharge}, #{prestigeCharge}, #{vihicleId}) + + + + + + + + + + + From 2b7da47833a308905388dd5963a7229dddb0544e Mon Sep 17 00:00:00 2001 From: DebbieIsFree Date: Mon, 20 May 2024 16:23:55 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat(#23)=20:=20=ED=95=AD=EA=B3=B5=EA=B6=8C?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=80=EC=9E=A5=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/EnjoyTripBackend/exception/ErrorCode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/exception/ErrorCode.java b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/exception/ErrorCode.java index 70880ac..833780b 100644 --- a/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/exception/ErrorCode.java +++ b/EnjoyTripBackend/src/main/java/com/example/EnjoyTripBackend/exception/ErrorCode.java @@ -21,7 +21,8 @@ public enum ErrorCode { FAIL_INSERT_GOLF_DATA(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스에 골프 데이터 저장에 실패하였습니다"), FAIL_COMMUNICATE_TOSSPAYMENT_API(HttpStatus.INTERNAL_SERVER_ERROR,"토스페이먼트 API와의 통신에 실패하였습니다."), FAIL_COMMUNICATE_EXTERNAL_API(HttpStatus.INTERNAL_SERVER_ERROR,"외부 API와의 통신에 실패하였습니다."), - Limited_Size_Pagination(HttpStatus.INTERNAL_SERVER_ERROR,"최대 페이징 사이지를 초과하였습니다."); + Limited_Size_Pagination(HttpStatus.INTERNAL_SERVER_ERROR,"최대 페이징 사이지를 초과하였습니다."), + FAIL_INSERT_AIRPLANE_DATA(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스에 항공권 데이터 저장에 실패하였습니다"); private final HttpStatus httpstatus; private final String message;