-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from tukcomCD2024/backend/feature/25-amadeus-api
[Backend] feat : Amadeus API - 항공편 조회
- Loading branch information
Showing
10 changed files
with
273 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
backend/src/main/java/com/isp/backend/domain/flight/controller/FlightOfferController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.isp.backend.domain.flight.controller; | ||
|
||
import com.amadeus.exceptions.ResponseException; | ||
import com.isp.backend.domain.flight.service.FlightOfferService; | ||
import com.isp.backend.domain.flight.dto.FlightSearchRequestDTO; | ||
import com.isp.backend.global.security.CustomUserDetails; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/bookings/flights") | ||
@RequiredArgsConstructor | ||
public class FlightOfferController { | ||
|
||
@Autowired | ||
private FlightOfferService flightOfferService; | ||
|
||
/** | ||
* 항공권 검색 API | ||
*/ | ||
@GetMapping("/search") | ||
public ResponseEntity<String> getFlightOffers(@AuthenticationPrincipal CustomUserDetails customUserDetails, | ||
@RequestBody FlightSearchRequestDTO request) { | ||
String memberUid = customUserDetails.getUsername(); | ||
try { | ||
String flightOffersJson = flightOfferService.getFlightOffers(request); | ||
return ResponseEntity.ok(flightOffersJson); | ||
} catch (ResponseException e) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error occurred while fetching flight offers"); | ||
} | ||
} | ||
|
||
|
||
} |
28 changes: 28 additions & 0 deletions
28
backend/src/main/java/com/isp/backend/domain/flight/dto/FlightSearchRequestDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.isp.backend.domain.flight.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
@Getter | ||
public class FlightSearchRequestDTO { | ||
|
||
private String originCity; | ||
|
||
private String destinationCity; | ||
|
||
private String departureDate; | ||
|
||
private String returnDate; | ||
|
||
private int adults; | ||
|
||
private int children; | ||
|
||
private int max ; | ||
|
||
private boolean nonStop ; // 직항 항공편 유무 | ||
|
||
} |
101 changes: 101 additions & 0 deletions
101
backend/src/main/java/com/isp/backend/domain/flight/mapper/FlightOfferProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package com.isp.backend.domain.flight.mapper; | ||
|
||
import com.google.gson.Gson; | ||
import com.google.gson.JsonArray; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonObject; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.time.Duration; | ||
import java.time.LocalDateTime; | ||
import java.time.format.DateTimeFormatter; | ||
|
||
@Service | ||
public class FlightOfferProcessor { | ||
|
||
/** 추출한 정보 json으로 반환 **/ | ||
public String processFlightOffers(String flightOffersJson) { | ||
// JSON 형식의 항공편 정보 -> JsonObject로 변환 | ||
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); | ||
} | ||
|
||
// 새로운 JsonArray를 JSON 형식으로 변환하여 반환 | ||
return filteredFlightOffers.toString(); | ||
} | ||
|
||
|
||
/** 항공 정보에서 필요한 정보 추출 **/ | ||
public JsonObject filterFlightOffer(JsonObject flightOffer) { | ||
JsonObject filteredFlightOffer = new JsonObject(); | ||
filteredFlightOffer.addProperty("id", flightOffer.get("id").getAsString()); | ||
filteredFlightOffer.addProperty("numberOfBookableSeats", flightOffer.get("numberOfBookableSeats").getAsInt()); | ||
|
||
// 여행 일정 - itineraries | ||
JsonArray itineraries = flightOffer.getAsJsonArray("itineraries"); | ||
JsonArray filteredItineraries = new JsonArray(); | ||
for (JsonElement itineraryElement : itineraries) { | ||
JsonObject itinerary = itineraryElement.getAsJsonObject(); | ||
JsonObject filteredItinerary = new JsonObject(); | ||
|
||
// duration 추출 | ||
formatDuration(itinerary, filteredItinerary); | ||
// filteredItinerary.addProperty("duration", itinerary.get("duration").getAsString()); // 비행 시간 | ||
|
||
|
||
// segments 추출 | ||
JsonArray segments = itinerary.getAsJsonArray("segments"); | ||
JsonArray filteredSegments = new JsonArray(); | ||
for (JsonElement segmentElement : segments) { | ||
JsonObject segment = segmentElement.getAsJsonObject(); | ||
JsonObject filteredSegment = new JsonObject(); | ||
|
||
// 출발편 | ||
filteredSegment.addProperty("departureIataCode", segment.getAsJsonObject("departure").get("iataCode").getAsString()); | ||
formatTime(segment.getAsJsonObject("departure").get("at").getAsString(), filteredSegment, "departureTime"); | ||
// 도착편 | ||
filteredSegment.addProperty("arrivalIataCode", segment.getAsJsonObject("arrival").get("iataCode").getAsString()); | ||
formatTime(segment.getAsJsonObject("arrival").get("at").getAsString(), filteredSegment, "arrivalTime"); | ||
|
||
filteredSegments.add(filteredSegment); | ||
} | ||
filteredItinerary.add("segments", filteredSegments); | ||
filteredItineraries.add(filteredItinerary); | ||
} | ||
filteredFlightOffer.add("itineraries", filteredItineraries); | ||
|
||
// 가격 정보 추출 | ||
JsonObject price = flightOffer.getAsJsonObject("price"); | ||
// filteredFlightOffer.addProperty("currency", price.get("currency").getAsString()); | ||
filteredFlightOffer.addProperty("totalPrice", price.get("total").getAsString()); | ||
|
||
return filteredFlightOffer; | ||
} | ||
|
||
|
||
/** 시간 변환 **/ | ||
private void formatTime(String timeStr, JsonObject filteredSegment, String propertyName) { | ||
LocalDateTime time = LocalDateTime.parse(timeStr, DateTimeFormatter.ISO_DATE_TIME); | ||
String formattedTime = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); | ||
filteredSegment.addProperty(propertyName, formattedTime); | ||
} | ||
|
||
/** duration 비행 시간 변환 **/ | ||
private void formatDuration(JsonObject itinerary, JsonObject filteredItinerary) { | ||
String durationString = itinerary.get("duration").getAsString(); | ||
Duration duration = Duration.parse(durationString); | ||
long hours = duration.toHours(); | ||
long minutes = duration.minusHours(hours).toMinutes(); | ||
String formattedDuration = String.format("%d:%02d", hours, minutes); | ||
filteredItinerary.addProperty("duration", formattedDuration); | ||
} | ||
|
||
|
||
} | ||
|
64 changes: 64 additions & 0 deletions
64
backend/src/main/java/com/isp/backend/domain/flight/service/FlightOfferService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.isp.backend.domain.flight.service; | ||
|
||
import com.amadeus.Amadeus; | ||
import com.amadeus.Params; | ||
import com.amadeus.exceptions.ResponseException; | ||
import com.amadeus.resources.FlightOfferSearch; | ||
import com.google.gson.Gson; | ||
import com.isp.backend.domain.country.entity.Country; | ||
import com.isp.backend.domain.country.repository.CountryRepository; | ||
import com.isp.backend.domain.flight.dto.FlightSearchRequestDTO; | ||
import com.isp.backend.domain.flight.mapper.FlightOfferProcessor; | ||
import com.isp.backend.global.exception.schedule.CountryNotFoundException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
@Service | ||
public class FlightOfferService { | ||
|
||
private final Amadeus amadeus; | ||
private final CountryRepository countryRepository; | ||
private final FlightOfferProcessor flightOfferProcessor ; | ||
|
||
|
||
/** | ||
* 항공편 조회 | ||
*/ | ||
public String getFlightOffers(FlightSearchRequestDTO request) throws ResponseException { | ||
|
||
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") // 원화 설정 - 추후 유저에게 입력받을 수 있게 변경 | ||
); | ||
|
||
// FlightOfferSearch 배열을 JSON 문자열로 변환 | ||
Gson gson = new Gson(); | ||
String flightOffersJson = gson.toJson(flightOffers); | ||
return flightOfferProcessor.processFlightOffers(flightOffersJson); // 원하는 정보만 조회 | ||
} | ||
|
||
|
||
/** 공항 코드 찾기 **/ | ||
public String findAirportCode(String countryName) { | ||
Country findCountry = countryRepository.findAirportCodeByCity(countryName); | ||
if (findCountry == null) { | ||
throw new CountryNotFoundException(); | ||
} | ||
return findCountry.getAirportCode(); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
backend/src/main/java/com/isp/backend/global/security/AmadeusConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.isp.backend.global.security; | ||
|
||
import com.amadeus.Amadeus; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class AmadeusConfig { | ||
|
||
@Value("${api-key.amadeus.accessKey}") | ||
private String apiKey; | ||
|
||
@Value("${api-key.amadeus.secretKey}") | ||
private String apiSecret; | ||
|
||
@Bean | ||
public Amadeus getAmadeus(){ | ||
return Amadeus | ||
.builder(apiKey, apiSecret) | ||
.build(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters