diff --git a/backend/src/main/java/com/isp/backend/domain/flight/mapper/FlightOfferProcessor.java b/backend/src/main/java/com/isp/backend/domain/flight/mapper/FlightOfferProcessor.java index 3349cdcc..8e84539f 100644 --- a/backend/src/main/java/com/isp/backend/domain/flight/mapper/FlightOfferProcessor.java +++ b/backend/src/main/java/com/isp/backend/domain/flight/mapper/FlightOfferProcessor.java @@ -17,14 +17,12 @@ public class FlightOfferProcessor { public String processFlightOffers(String flightOffersJson) { JsonArray flightOffersArray = new Gson().fromJson(flightOffersJson, JsonArray.class); - // 필요한 정보만 객체로 변환 JsonArray filteredFlightOffers = new JsonArray(); for (JsonElement flightOfferElement : flightOffersArray) { JsonObject flightOffer = flightOfferElement.getAsJsonObject(); JsonObject filteredFlightOffer = filterFlightOffer(flightOffer); filteredFlightOffers.add(filteredFlightOffer); } - return filteredFlightOffers.toString(); } @@ -38,18 +36,15 @@ public JsonObject filterFlightOffer(JsonObject flightOffer) { .getAsJsonArray("segments").get(0).getAsJsonObject().get("carrierCode").getAsString(); Double price = flightOffer.getAsJsonObject("price").get("total").getAsDouble(); + // 왕복-편도 여행 여부 확인 (itineraries 배열 길이 확인) + boolean isRoundTrip = flightOffer.getAsJsonArray("itineraries").size() == 2; + // 출국 정보 추출 JsonObject abroadItinerary = flightOffer.getAsJsonArray("itineraries").get(0).getAsJsonObject(); String abroadDuration = abroadItinerary.get("duration").getAsString(); String abroadDepartureTime = abroadItinerary.getAsJsonArray("segments").get(0).getAsJsonObject().getAsJsonObject("departure").get("at").getAsString(); String abroadArrivalTime = abroadItinerary.getAsJsonArray("segments").get(0).getAsJsonObject().getAsJsonObject("arrival").get("at").getAsString(); - // 입국 정보 추출 - JsonObject homeItinerary = flightOffer.getAsJsonArray("itineraries").get(1).getAsJsonObject(); - String homeDuration = homeItinerary.get("duration").getAsString(); - String homeDepartureTime = homeItinerary.getAsJsonArray("segments").get(0).getAsJsonObject().getAsJsonObject("departure").get("at").getAsString(); - String homeArrivalTime = homeItinerary.getAsJsonArray("segments").get(1).getAsJsonObject().getAsJsonObject("arrival").get("at").getAsString(); - // 출발지 및 도착지 정보 추출 JsonArray segments = flightOffer.getAsJsonArray("itineraries").get(0).getAsJsonObject().getAsJsonArray("segments"); JsonObject lastSegment = segments.get(segments.size() - 1).getAsJsonObject(); @@ -62,34 +57,46 @@ public JsonObject filterFlightOffer(JsonObject flightOffer) { // 시간 변환 및 저장 String filteredAbroadDepartureTime = formatTime(abroadDepartureTime); String filteredAbroadArrivalTime = formatTime(abroadArrivalTime); - String filteredHomeDepartureTime = formatTime(homeDepartureTime); - String filteredHomeArrivalTime = formatTime(homeArrivalTime); // duration 변환 및 저장 - String filteredAbroadDuration = formatDuration(abroadItinerary); - String filteredHomeDuration = formatDuration(homeItinerary); + String filteredAbroadDuration = formatDuration(abroadDuration); // 경유 및 직항 여부 추출 boolean nonstop = segments.size() == 1; // 직항일 경우 segments 배열의 크기는 1이 됨 - // 필터링된 정보로 객체 생성 filteredFlightOffer.addProperty("id", id); filteredFlightOffer.addProperty("carrierCode", carrierCode); filteredFlightOffer.addProperty("totalPrice", price); - filteredFlightOffer.addProperty("abroadDuration", filteredAbroadDuration); - filteredFlightOffer.addProperty("abroadDepartureTime", filteredAbroadDepartureTime); - filteredFlightOffer.addProperty("abroadArrivalTime", filteredAbroadArrivalTime); - filteredFlightOffer.addProperty("homeDuration", filteredHomeDuration); - filteredFlightOffer.addProperty("homeDepartureTime", filteredHomeDepartureTime); - filteredFlightOffer.addProperty("homeArrivalTime", filteredHomeArrivalTime); filteredFlightOffer.addProperty("departureIataCode", departureIataCode); filteredFlightOffer.addProperty("arrivalIataCode", arrivalIataCode); filteredFlightOffer.addProperty("nonstop", nonstop); filteredFlightOffer.addProperty("transferCount", transferCount); + filteredFlightOffer.addProperty("abroadDuration", filteredAbroadDuration); + filteredFlightOffer.addProperty("abroadDepartureTime", filteredAbroadDepartureTime); + filteredFlightOffer.addProperty("abroadArrivalTime", filteredAbroadArrivalTime); + + + // 왕복 여행의 경우 + if (isRoundTrip) { + // 입국 여행 정보 추출 + JsonObject homeItinerary = flightOffer.getAsJsonArray("itineraries").get(1).getAsJsonObject(); + String homeDuration = homeItinerary.get("duration").getAsString(); + String homeDepartureTime = homeItinerary.getAsJsonArray("segments").get(0).getAsJsonObject().getAsJsonObject("departure").get("at").getAsString(); + String homeArrivalTime = homeItinerary.getAsJsonArray("segments").get(1).getAsJsonObject().getAsJsonObject("arrival").get("at").getAsString(); + String filteredHomeDepartureTime = formatTime(homeDepartureTime); + String filteredHomeArrivalTime = formatTime(homeArrivalTime); + String filteredHomeDuration = formatDuration(homeDuration); + + // 응답 값에 추가 + filteredFlightOffer.addProperty("homeDuration", filteredHomeDuration); + filteredFlightOffer.addProperty("homeDepartureTime", filteredHomeDepartureTime); + filteredFlightOffer.addProperty("homeArrivalTime", filteredHomeArrivalTime); + } return filteredFlightOffer; } + /** 경유 횟수 확인 **/ private int countTransfers(JsonArray segments) { // 직항일 경우 경유 없음 @@ -100,16 +107,18 @@ private int countTransfers(JsonArray segments) { return segments.size() - 1; } + /** 시간 변환 **/ private String formatTime(String timeStr) { LocalDateTime time = LocalDateTime.parse(timeStr, DateTimeFormatter.ISO_DATE_TIME); return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } + /** duration 비행 시간 변환 **/ - private String formatDuration(JsonObject itinerary) { - String durationString = itinerary.get("duration").getAsString(); - Duration duration = Duration.parse(durationString); + private String formatDuration(String durationStr) { + Duration duration = Duration.parse(durationStr); + long hours = duration.toHours(); long minutes = duration.minusHours(hours).toMinutes(); return String.format("%d:%02d", hours, minutes); diff --git a/backend/src/main/java/com/isp/backend/domain/flight/service/FlightOfferServiceImpl.java b/backend/src/main/java/com/isp/backend/domain/flight/service/FlightOfferServiceImpl.java index 9e17f911..af0aa450 100644 --- a/backend/src/main/java/com/isp/backend/domain/flight/service/FlightOfferServiceImpl.java +++ b/backend/src/main/java/com/isp/backend/domain/flight/service/FlightOfferServiceImpl.java @@ -47,17 +47,21 @@ public String getFlightOffers(FlightSearchRequest request) throws ResponseExcept String originLocationCode = findAirportCode(request.getOriginCity()); String destinationLocationCode = findAirportCode(request.getDestinationCity()); - FlightOfferSearch[] flightOffers = amadeus.shopping.flightOffersSearch.get( - Params.with("originLocationCode", originLocationCode) - .and("destinationLocationCode", destinationLocationCode) - .and("departureDate", request.getDepartureDate()) - .and("returnDate", request.getReturnDate()) - .and("adults", request.getAdults()) - .and("children", request.getChildren()) - .and("max", request.getMax()) - .and("nonStop", request.isNonStop()) - .and("currencyCode","KRW") // 원화 설정 -> 추후 유저에게 입력받을 수 있게 남겨둠 - ); + Params params = Params.with("originLocationCode", originLocationCode) + .and("destinationLocationCode", destinationLocationCode) + .and("departureDate", request.getDepartureDate()) + .and("adults", request.getAdults()) + .and("children", request.getChildren()) + .and("max", request.getMax()) + .and("nonStop", request.isNonStop()) + .and("currencyCode", "KRW"); // 원화 설정 -> 추후 유저에게 입력받을 수 있게 남겨둠 + + // returnDate가 빈 문자열이 아닌 경우에만 파라미터 추가 + if (request.getReturnDate() != null && !request.getReturnDate().isEmpty()) { + params.and("returnDate", request.getReturnDate()); + } + + FlightOfferSearch[] flightOffers = amadeus.shopping.flightOffersSearch.get(params); Gson gson = new Gson(); String flightOffersJson = gson.toJson(flightOffers); diff --git a/backend/src/main/java/com/isp/backend/domain/hotel/controller/HotelController.java b/backend/src/main/java/com/isp/backend/domain/hotel/controller/HotelController.java index a9de215e..ad575365 100644 --- a/backend/src/main/java/com/isp/backend/domain/hotel/controller/HotelController.java +++ b/backend/src/main/java/com/isp/backend/domain/hotel/controller/HotelController.java @@ -1,16 +1,42 @@ package com.isp.backend.domain.hotel.controller; +import com.amadeus.exceptions.ResponseException; +import com.isp.backend.domain.hotel.dto.request.SearchGeocodeRequest; +import com.isp.backend.domain.hotel.service.HotelService; +import com.isp.backend.global.exception.flight.AmadeusSearchFailedException; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/bookings/hotels") @RequiredArgsConstructor public class HotelController { + private final HotelService hotelService ; /** 좌표 주변 호텔 리스트 API **/ + @PostMapping("/search") + public ResponseEntity searchHotelsByGeocode(@RequestBody SearchGeocodeRequest request) { + try { + String hotelsJson = hotelService.searchHotelsByGeocode(request); + return ResponseEntity.ok(hotelsJson); + } catch (ResponseException e) { + throw new AmadeusSearchFailedException(); + } + } + + /** 호텔 선택시 스카이스캐너 사이트로 연결 API **/ + + + /** 호텔 좋아요 저장 API **/ + + + /** 호텔 좋아요 목록 불러오기 API **/ + + + /** 호텔 좋아요 삭제하기 API **/ + diff --git a/backend/src/main/java/com/isp/backend/domain/hotel/dto/request/SearchGeocodeRequest.java b/backend/src/main/java/com/isp/backend/domain/hotel/dto/request/SearchGeocodeRequest.java index 8cdcabdf..3069b085 100644 --- a/backend/src/main/java/com/isp/backend/domain/hotel/dto/request/SearchGeocodeRequest.java +++ b/backend/src/main/java/com/isp/backend/domain/hotel/dto/request/SearchGeocodeRequest.java @@ -13,5 +13,8 @@ public class SearchGeocodeRequest { private String longitude; + private int radius ; + + private String ratings ; // 호텔 등급 } diff --git a/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelService.java b/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelService.java new file mode 100644 index 00000000..bc4fd247 --- /dev/null +++ b/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelService.java @@ -0,0 +1,10 @@ +package com.isp.backend.domain.hotel.service; + +import com.amadeus.exceptions.ResponseException; +import com.amadeus.resources.Hotel; +import com.isp.backend.domain.hotel.dto.request.SearchGeocodeRequest; + +public interface HotelService { + public String searchHotelsByGeocode(SearchGeocodeRequest request) throws ResponseException; + +} diff --git a/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelServiceImpl.java b/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelServiceImpl.java new file mode 100644 index 00000000..b1d88ea6 --- /dev/null +++ b/backend/src/main/java/com/isp/backend/domain/hotel/service/HotelServiceImpl.java @@ -0,0 +1,44 @@ +package com.isp.backend.domain.hotel.service; + +import com.amadeus.Amadeus; +import com.amadeus.Params; +import com.amadeus.exceptions.ResponseException; +import com.amadeus.resources.Hotel; +import com.amadeus.shopping.HotelOffersSearch; +import com.google.gson.Gson; +import com.isp.backend.domain.hotel.dto.request.SearchGeocodeRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class HotelServiceImpl implements HotelService { + private final Amadeus amadeus; + + /** + * 좌표 주변 호텔 리스트 API + **/ + @Override + public String searchHotelsByGeocode(SearchGeocodeRequest request) throws ResponseException { + String latitude = request.getLatitude(); + String longitude = request.getLongitude(); + int radius = request.getRadius(); + String ratings = request.getRatings(); + + Hotel[] hotelSearch = amadeus.referenceData.locations.hotels.byGeocode.get( + Params.with("latitude", latitude) + .and("longitude", longitude) + .and("radius", radius) + .and("radiusUnit", "KM") + .and("ratings", ratings) + .and("hotelSource", "ALL") + ); + Gson gson = new Gson(); + String hotelSearchJson = gson.toJson(hotelSearch); + return hotelSearchJson; + } + + +}