JavaRush /Java Blog /Random-TL /Paglikha ng sistema ng pagsubaybay sa presyo ng air ticke...

Paglikha ng sistema ng pagsubaybay sa presyo ng air ticket: isang sunud-sunod na gabay [Bahagi 1]

Nai-publish sa grupo

Nilalaman:

Paglikha ng isang sistema para sa pagsubaybay sa mga presyo ng air ticket: isang sunud-sunod na gabay [Bahagi 1] - 1Kumusta sa lahat, komunidad ng JavaRush! Ngayon ay pag-uusapan natin kung paano magsulat ng isang Spring Boot application para sa pagsubaybay sa mga presyo ng air ticket nang sunud-sunod. Ang artikulo ay inilaan para sa mga taong may ideya tungkol sa:
  • REST at kung paano binuo ang mga REST endpoint;
  • mga database ng relasyon;
  • ang gawain ng maven (sa partikular, kung ano ang dependency);
  • object ng JSON;
  • mga prinsipyo ng pag-log.
Inaasahang pag-uugali:
  1. Maaari kang pumili ng isang flight para sa isang partikular na petsa at subaybayan ang presyo para dito. Nakikilala ang user sa pamamagitan ng email address. Sa sandaling magawa ang isang subscription sa pagbabago ng presyo, makakatanggap ang user ng notification sa pamamagitan ng email.
  2. Bawat 30 minuto (ang agwat na ito ay na-configure sa pamamagitan ng application.properties) ang minimum na presyo para sa isang flight ay muling kinakalkula para sa lahat ng mga subscription. Kung ang isa sa mga halaga ay naging mas mababa, ang user ay makakatanggap ng isang abiso sa pamamagitan ng email.
  3. Ang lahat ng mga subscription na may hindi napapanahong petsa ng flight ay tatanggalin.
  4. Sa pamamagitan ng REST API maaari kang:
    • lumikha ng isang subscription;
    • i-edit;
    • tumanggap ng lahat ng mga subscription sa pamamagitan ng email;
    • tanggalin ang subscription.

Plano ng aksyon upang makamit ang layunin

Kailangan mong magsimula sa katotohanan na ang impormasyon tungkol sa mga flight ay kailangang kunin mula sa isang lugar. Karaniwan, ang mga website ay nagbibigay ng bukas na REST API kung saan maaaring makuha ang impormasyon.

Ang API (application programming interface) ay isang interface kung saan maaari kang makipag-ugnayan sa isang application. Mula dito maaari tayong bumuo ng tulay sa kung ano ang REST API.

Ang REST API ay isang interface ng mga kahilingan sa REST na maaaring magamit upang makipag-ugnayan sa isang web application.

Upang gawin ito, gagamitin namin ang Skyscanner , o sa halip, ang API (sa website ng Rakuten API ). Susunod, kailangan mong piliin ang tamang balangkas bilang pangunahing pundasyon. Ang pinakasikat at in demand ay ang Spring ecosystem at ang korona ng kanilang paglikha - Spring Boot. Maaari kang pumunta sa kanilang opisyal na website, o maaari mong basahin ang artikulo sa Habré . Upang mag-imbak ng mga subscription ng user, gagamitin namin ang built-in na H2 database . Upang magbasa mula sa JSON hanggang sa mga klase at pabalik, gagamitin namin ang Jackson Project ( narito ang link sa aming mapagkukunan ). Gagamit kami ng spring-boot-starter-mail upang magpadala ng mga mensahe sa mga user . Upang muling kalkulahin ng application ang pinakamababang presyo sa ibinigay na dalas, gagamitin namin ang Spring Scheduler . Upang lumikha ng REST API gagamitin namin ang spring-boot-starter-web . Upang hindi magsulat ng hiniram na code (getters, setters, override equals at hashcode, toString() para sa mga object), gagamitin namin ang Project Lombok . Upang maramdaman at makita ang REST API, gagamitin namin ang Swagger 2 at kaagad na Swagger UI (user interface) para sa real-time na pagsubaybay. Ganito ang hitsura ngayon: Paglikha ng sistema ng pagsubaybay sa presyo ng tiket sa himpapawid: isang hakbang-hakbang na gabay [Bahagi 1] - 2kung saan mayroong 4 na pahinga na mga query na tumutugma sa paggawa, pag-edit, pagkuha at pagtanggal ng mga subscription.

Paggalugad sa Skyscanner API

Sundan natin ang link sa rakuten api . Kailangan mo munang magparehistro. Paglikha ng sistema ng pagsubaybay sa presyo ng tiket sa himpapawid: isang hakbang-hakbang na gabay [Bahagi 1] - 3Ang lahat ng ito ay kailangan para makatanggap ng isang natatanging key para magamit ang kanilang site at gumawa ng mga kahilingan sa mga pampublikong API na naka-post dito. Ang isa sa mga API na ito ay ang Skyscanner Flight Search na kailangan namin . Ngayon, alamin natin kung paano ito gumagana. Hanapin natin ang kahilingan sa GET List Places. Ipinapakita ng larawan na kailangan mong punan ang data at simulan ang Test Endpoint , bilang isang resulta kung saan nakatanggap kami ng tugon sa anyo ng isang JSON object sa kanan: Paglikha ng isang sistema para sa pagsubaybay sa mga presyo ng air ticket: isang sunud-sunod na gabay [Bahagi 1] - 4at ang kahilingan ay gagawin tulad nito:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
at lahat ng mga parameter ay papalitan sa formula na ito, makukuha natin ang:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
at dalawang header ang ipapasa sa mga kahilingang ito:

.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
kung saan sign-up-for-keyibinibigay ito pagkatapos ng pagpaparehistro. Upang subaybayan ang pagbaba ng presyo, kakailanganin namin ang endpoint ng Browse Quotes . hanapin mo sarili mo :)

Paglikha ng balangkas ng application batay sa Spring Boot

Upang mabilis at madaling gumawa ng proyekto gamit ang Spring Boot, maaari mong gamitin ang Spring Initializr . Piliin ang mga sumusunod na opsyon:
  1. Maven project
  2. Java
  3. 2.1.10
  4. grupo - alinman sa tingin mo ay kinakailangan, halimbawa ru.javarush
  5. artifact - eksaktong pareho, halimbawa flight-monitoring
  6. sa paghahanap ng dependency hinahanap namin ang mga sumusunod:
    • Spring Web
    • Java Mail Sender
    • Spring Data Jpa
    • H2 Database
At pagkatapos ay i-click ang Bumuo . Iyon lang: ang natapos na proyekto ay mada-download bilang isang archive. Kung may hindi gumana, maaari mong gamitin ang link kung saan na-save ko ang gustong proyekto . Siyempre, mas mahusay na gawin ito sa iyong sarili at maunawaan kung paano ito gumagana. Ang application ay binubuo ng tatlong layer:
  • CONTROLLER - mag-login sa application. Ang REST API ay ilalarawan dito
  • Ang SERVICE ay isang business logic layer. Ang buong lohika ng application ay ilalarawan dito.
  • REPOSITORY - layer para sa pagtatrabaho sa database.
Gayundin, ang mga klase na nauugnay sa kliyente para sa Skyscanner Flight Search API ay magiging isang hiwalay na pakete.

Sumulat kami ng isang kliyente para sa mga kahilingan sa Skyscanner Flight Search API sa proyekto

Mabait na nagbigay ang Skyscanner ng artikulo sa kung paano gamitin ang kanilang API (hindi kami gagawa ng session na may aktibong kahilingan). Ano ang ibig sabihin ng "magsulat ng isang kliyente"? Kailangan naming gumawa ng kahilingan sa isang partikular na URL na may ilang partikular na parameter at maghanda ng DTO (data transfer object) para sa data na inilipat pabalik sa amin. Mayroong apat na pangkat ng mga kahilingan sa site:
  1. Live na Paghahanap ng Flight - hindi namin ito ituturing na hindi kailangan sa ngayon.
  2. Mga lugar - magsulat tayo.
  3. Mag-browse ng Mga Presyo ng Flight - gagamit kami ng isang kahilingan kung saan makukuha mo ang lahat ng impormasyon.
  4. Lokalisasyon - idagdag natin ito para malaman natin kung anong data ang sinusuportahan.

Lumikha ng serbisyo ng kliyente para sa kahilingan sa Lokalisasyon:

Ang plano ay kasing simple ng isang steamed turnip: lumikha ng isang kahilingan, tingnan ang mga parameter, tingnan ang tugon. Mayroong dalawang query: Mga marker ng listahan at Mga Pera. Magsimula tayo sa Currencies. Ipinapakita ng figure na ito ay isang kahilingan nang walang karagdagang mga field: ito ay kinakailangan upang makakuha ng impormasyon tungkol sa mga sinusuportahang pera: Paglikha ng sistema ng pagsubaybay sa presyo ng tiket sa himpapawid: isang hakbang-hakbang na gabay [Bahagi 1] - 6Ang tugon ay nasa anyo ng isang JSON object, na naglalaman ng isang koleksyon ng parehong mga bagay, halimbawa:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Gumawa tayo ng CurrencyDto para sa bagay na ito:
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

/**
* Data transfer object for Currency.
*/
@Data
public class CurrencyDto {

   @JsonProperty("Code")
   private String code;

   @JsonProperty("Symbol")
   private String symbol;

   @JsonProperty("ThousandsSeparator")
   private String thousandsSeparator;

   @JsonProperty("DecimalSeparator")
   private String decimalSeparator;

   @JsonProperty("SymbolOnLeft")
   private boolean symbolOnLeft;

   @JsonProperty("SpaceBetweenAmountAndSymbol")
   private boolean spaceBetweenAmountAndSymbol;

   @JsonProperty("RoundingCoefficient")
   private int roundingCoefficient;

   @JsonProperty("DecimalDigits")
   private int decimalDigits;
}
saan:
  • Ang @Data ay isang anotasyon mula sa proyekto ng Lombok at bumubuo ng lahat ng getter, setter, override saString(), equals() at hashCode() na mga pamamaraan. Ano ang nagpapabuti sa pagiging madaling mabasa ng code at nagpapabilis sa oras ng pagsulat ng mga bagay ng POJO ;
  • Ang @JsonProperty("Code") ay isang anotasyon mula sa Jackson Project na nagsasabi kung anong field ang itatalaga sa variable na ito. Iyon ay, isang field sa JSON na katumbas ng Code ang itatalaga sa code variable .
Iminumungkahi ng opisyal na artikulo mula sa Skyscanner ang paggamit ng UniRest library para sa mga kahilingan sa REST . Samakatuwid, magsusulat kami ng isa pang serbisyo na magpapatupad ng mga kahilingan sa pamamagitan ng REST. Ito ay magiging UniRestService . Upang gawin ito, magdagdag ng bagong dependency sa maven:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Susunod, magsusulat kami ng isang serbisyo na magsasagawa ng mga kahilingan sa REST. Siyempre, para sa bawat kliyente/serbisyo gagawa kami ng interface at pagpapatupad nito:
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;

/**
* Service, which is manipulating with Rest calls.
*/
public interface UniRestService {

   /**
   * Create GET request based on provided {@param path} with needed headers.
   *
   * @param path provided path with all the needed data
   * @return {@link HttpResponse<jsonnode>} response object.
   */
   HttpResponse<jsonnode> get(String path);

}
At ang pagpapatupad nito:
import com.github.romankh3.flightsmonitoring.exception.FlightClientException;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
* {@inheritDoc}
*/
@Slf4j
@Service
public class UniRestServiceImpl implements UniRestService {

   public static final String HOST = "https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com";

   public static final String PLACES_FORMAT = "/apiservices/autosuggest/v1.0/%s/%s/%s/?query=%s";
   public static final String CURRENCIES_FORMAT = "/apiservices/reference/v1.0/currencies";
   public static final String COUNTRIES_FORMAT = "/apiservices/reference/v1.0/countries/%s";

   public static final String PLACES_KEY = "Places";
   public static final String CURRENCIES_KEY = "Currencies";
   public static final String COUNTRIES_KEY = "Countries";

   @Value("${x.rapid.api.key}")
   private String xRapidApiKey;

   /**
    * {@inheritDoc}
    */
   @Override
   public HttpResponse<jsonnode> get(String path) {
       HttpResponse<jsonnode> response = null;
       try {
           response = Unirest.get(HOST + path)
                   .header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
                   .header("x-rapidapi-key", xRapidApiKey)
                   .asJson();
       } catch (UnirestException e) {
           throw new FlightClientException(String.format("Request failed, path=%s", HOST + path), e);
       }

       log.info("Response from Get request, on path={}, statusCode={}, response={}", path, response.getStatus(), response.getBody().toString());
       return response;
   }
}
Ang kakanyahan nito ay ang lahat ng mga kahilingan na interesado kami ay nilikha para sa mga kahilingan sa GET, at ang serbisyong ito ay tumatanggap ng isang handa na kahilingan at nagdaragdag ng mga kinakailangang header tulad ng:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Upang kumuha ng data mula sa mga property, gamitin ang @Value annotation gaya ng ipinapakita sa ibaba:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Sinasabi nito na sa application.properties magkakaroon ng property na pinangalanang x.rapid.api.key, na kailangang i-inject sa variable na ito. Inaalis namin ang mga hardcoded na halaga at nakukuha ang kahulugan ng variable na ito mula sa program code. Bukod dito, kapag nai-publish ko ang application na ito sa GitHub hindi ko idinaragdag ang halaga ng property na ito. Ginagawa ito para sa mga kadahilanang pangseguridad. Nagsulat kami ng isang serbisyo na gagana sa mga kahilingan ng REST, ngayon ay oras na para sa isang serbisyo para sa Lokalisasyon. Gumagawa kami ng isang application batay sa OOP, kaya lumikha kami ng interface ng LocalizationClient at ang pagpapatupad nito LocalisationClientImpl :
import com.github.romankh3.flightsmonitoring.client.dto.CountryDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import java.io.IOException;
import java.util.List;

/**
* Client for SkyScanner localisation.
*/
public interface LocalisationClient {

   /**
    * Retrieve the market countries that SkyScanner flight search API support. Most suppliers (airlines,
    * travel agents and car hire dealers) set their fares based on the market (or country of purchase).
    * It is therefore necessary to specify the market country in every query.
    *
    * @param locale locale of the response.
    *
    * @return the collection of the {@link CountryDto} objects.
    *
    * @throws IOException
    */
   List<CountryDto> retrieveCountries(String locale);

   /**
    * Retrieve the currencies that we ScyScanner flight search API.
    *
    * @return the collection of the {@link CurrencyDto} objects.
    *
    * @throws IOException
    */
   List<CurrencyDto> retrieveCurrencies();

}
at pagpapatupad ng LocalizationClientImpl
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.COUNTRIES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.COUNTRIES_KEY;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_KEY;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.CountryDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import com.github.romankh3.flightsmonitoring.client.service.LocalisationClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* {@inheritDoc}
*/
@Component
public class LocalisationClientImpl implements LocalisationClient {

   @Autowired
   private UniRestService uniRestService;

   @Autowired
   private ObjectMapper objectMapper;

   /**
    * {@inheritDoc}
    */
   @Override
   public List<CountryDto> retrieveCountries(String locale) throws IOException {
       HttpResponse<JsonNode> response = uniRestService.get(String.format(COUNTRIES_FORMAT, locale));

       if (response.getStatus() != HttpStatus.SC_OK) {
           return null;
       }

       String jsonList = response.getBody().getObject().get(COUNTRIES_KEY).toString();

       return objectMapper.readValue(jsonList, new TypeReference<List<CountryDto>>() {
       });
   }

   /**
    * {@inheritDoc}
    */
   @Override
   public List<CurrencyDto> retrieveCurrencies() throws IOException, UnirestException {

       HttpResponse<JsonNode> response = uniRestService.get(CURRENCIES_FORMAT);
       if (response.getStatus() != HttpStatus.SC_OK) {
           return null;
       }

       String jsonList = response.getBody().getObject().get(CURRENCIES_KEY).toString();

       return objectMapper.readValue(jsonList, new TypeReference<List<CurrencyDto>>() {
       });
   }
}
saan
  • Ang @Autowired ay isang anotasyon na nagsasabing kailangan mong mag-inject ng isang bagay sa klase na ito at gamitin ito nang hindi ito ginagawa, iyon ay, nang walang bagong operasyon ng Bagay;
  • Ang @Component ay isang anotasyon na nagsasabing ang bagay na ito ay dapat idagdag sa Konteksto ng Application upang ito ay ma-inject sa ibang pagkakataon gamit ang @Autowired annotation;
  • Ang ObjectMapper objectMapper ay isang object mula sa Jackson Project na nagsasalin ng lahat ng ito sa Java objects.
  • CurrencyDTO at CountryDto:
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

/**
* Data transfer object for Currency.
*/
@Data
public class CurrencyDto {

   @JsonProperty("Code")
   private String code;

   @JsonProperty("Symbol")
   private String symbol;

   @JsonProperty("ThousandsSeparator")
   private String thousandsSeparator;

   @JsonProperty("DecimalSeparator")
   private String decimalSeparator;

   @JsonProperty("SymbolOnLeft")
   private boolean symbolOnLeft;

   @JsonProperty("SpaceBetweenAmountAndSymbol")
   private boolean spaceBetweenAmountAndSymbol;

   @JsonProperty("RoundingCoefficient")
   private int roundingCoefficient;

   @JsonProperty("DecimalDigits")
   private int decimalDigits;
}
	и
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

/**
* Data transfer object for Country.
*/
@Data
public class CountryDto {

   @JsonProperty("Code")
   private String code;

   @JsonProperty("Name")
   private String name;
}
Upang mag-inject ng isang ObjectMapper sa anumang bahagi ng proyekto, idinagdag ko ang paglikha at pagdaragdag nito sa ApplicationContext sa pamamagitan ng isang klase ng pagsasaayos.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* {@link Configuration} class.
*/
@Configuration
public class Config {

   @Bean
   public ObjectMapper objectMapper() {
       ObjectMapper objectMapper = new ObjectMapper();
       objectMapper.registerModule(new JavaTimeModule());
       return objectMapper;
   }
}
Ang @Configuration annotation ay nagsasabi sa Spring na magkakaroon ng ilang mga configuration sa klase na ito. At para lamang dito idinagdag ko ang ObjectMapper. Katulad nito, nagdagdag kami ng PlacesClient at PlacesClientImpl:
import com.github.romankh3.flightsmonitoring.client.dto.PlaceDto;
import com.github.romankh3.flightsmonitoring.client.dto.PlacesDto;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;

/**
* SkyScanner client.
*/
public interface PlacesClient {

   /**
    * Get a list of places that match a query string based on arguments.
    *
    * @param query the code of the city.
    * @param country the code of the country.
    * @param currency the code of the currency.
    * @param locale the code of the locale.
    * @return the collection of the {@link PlaceDto} objects.
    */
   List<PlacesDto> retrieveListPlaces(String query, String country, String currency, String locale)
           throws IOException, UnirestException;
}
at
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_KEY;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.PlacesDto;
import com.github.romankh3.flightsmonitoring.client.service.PlacesClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* {@inheritDoc}
*/
@Service
public class PlacesClientImpl implements PlacesClient {

   @Autowired
   private UniRestService uniRestService;

   @Autowired
   private ObjectMapper objectMapper;


   /**
    * {@inheritDoc}
    */
   @Override
   public List<PlacesDto> retrieveListPlaces(String query, String country, String currency, String locale)
           throws IOException, UnirestException {
       HttpResponse<JsonNode> response = uniRestService
               .get(String.format(PLACES_FORMAT, country, currency, locale, query));

       if (response.getStatus() != HttpStatus.SC_OK) {
           return null;
       }

       String jsonList = response.getBody().getObject().get(PLACES_KEY).toString();

       return objectMapper.readValue(jsonList, new TypeReference<List<PlacesDto>>() {
       });
   }
}
kung saan may form ang PlacesDto:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.romankh3.flightsmonitoring.client.service.PlacesClient;
import lombok.Data;

/**
* Using for {@link PlacesClient}.
*/
@Data
public class PlacesDto {

   @JsonProperty("PlaceId")
   private String placeId;

   @JsonProperty("PlaceName")
   private String placeName;

   @JsonProperty("CountryId")
   private String countryId;

   @JsonProperty("RegionId")
   private String regionId;

   @JsonProperty("CityId")
   private String cityId;

   @JsonProperty("CountryName")
   private String countryName;
}
At sa wakas, isang serbisyo ng kliyente na, batay sa kinakailangang data, ay magbabalik ng pinakamababang presyo para sa isang flight at lahat ng kinakailangang impormasyon: FlightPriceClient at FlightPriceClientImpl. Isang kahilingan lang ang ipapatupad namin, browseQuotes. FlightPriceClient:
import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto;

/**
* Browse flight prices.
*/
public interface FlightPricesClient {

   /**
    * Browse quotes for current flight based on provided arguments. One-way ticket.
    *
    * @param country the country from
    * @param currency the currency to get price
    * @param locale locale for the response
    * @param originPlace origin place
    * @param destinationPlace destination place
    * @param outboundPartialDate outbound date
    * @return {@link FlightPricesDto} object.
    */
   FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
           String destinationPlace, String outboundPartialDate);

   /**
    * Browse quotes for current flight based on provided arguments. Round trip ticket.
    *
    * @param country the country from
    * @param currency the currency to get price
    * @param locale locale for the response
    * @param originPlace origin place
    * @param destinationPlace destination place
    * @param outboundPartialDate outbound date
    * @param inboundPartialDate inbound date
    * @return {@link FlightPricesDto} object.
    */
   FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
           String destinationPlace, String outboundPartialDate, String inboundPartialDate);
}
FlightPriceClientImpl
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_KEY;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_KEY;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.CarrierDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto;
import com.github.romankh3.flightsmonitoring.client.dto.PlaceDto;
import com.github.romankh3.flightsmonitoring.client.dto.QuoteDto;
import com.github.romankh3.flightsmonitoring.client.dto.ValidationErrorDto;
import com.github.romankh3.flightsmonitoring.client.service.FlightPricesClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.github.romankh3.flightsmonitoring.exception.FlightClientException;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* {@inheritDoc}
*/
@Service
public class FlightPricesClientImpl implements FlightPricesClient {

   public static final String BROWSE_QUOTES_FORMAT = "/apiservices/browsequotes/v1.0/%s/%s/%s/%s/%s/%s";
   public static final String OPTIONAL_BROWSE_QUOTES_FORMAT = BROWSE_QUOTES_FORMAT + "?inboundpartialdate=%s";

   public static final String QUOTES_KEY = "Quotes";
   public static final String ROUTES_KEY = "Routes";
   public static final String DATES_KEY = "Dates";
   public static final String CARRIERS_KEY = "Carriers";
   public static final String VALIDATIONS_KEY = "ValidationErrors";

   @Autowired
   private UniRestService uniRestService;

   @Autowired
   private ObjectMapper objectMapper;

   /**
    * {@inheritDoc}
    */
   @Override
   public FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
           String destinationPlace, String outboundPartialDate) {

       HttpResponse<JsonNode> response = uniRestService.get(String
               .format(BROWSE_QUOTES_FORMAT, country, currency, locale, originPlace, destinationPlace,
                       outboundPartialDate));
       return mapToObject(response);
   }

   public FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
           String destinationPlace, String outboundPartialDate, String inboundPartialDate) {
       HttpResponse<JsonNode> response = uniRestService.get(String
               .format(OPTIONAL_BROWSE_QUOTES_FORMAT, country, currency, locale, originPlace, destinationPlace,
                       outboundPartialDate, inboundPartialDate));
       return mapToObject(response);
   }

   private FlightPricesDto mapToObject(HttpResponse<JsonNode> response) {
       if (response.getStatus() == HttpStatus.SC_OK) {
           FlightPricesDto flightPricesDto = new FlightPricesDto();
           flightPricesDto.setQuotas(readValue(response.getBody().getObject().get(QUOTES_KEY).toString(),
                   new TypeReference<List<QuoteDto>>() {
                   }));
           flightPricesDto.setCarriers(readValue(response.getBody().getObject().get(CARRIERS_KEY).toString(),
                   new TypeReference<List<CarrierDto>>() {
                   }));
           flightPricesDto.setCurrencies(readValue(response.getBody().getObject().get(CURRENCIES_KEY).toString(),
                   new TypeReference<List<CurrencyDto>>() {
                   }));
           flightPricesDto.setPlaces(readValue(response.getBody().getObject().get(PLACES_KEY).toString(),
                   new TypeReference<List<PlaceDto>>() {
                   }));
           return flightPricesDto;
       }
       throw new FlightClientException(String.format("There are validation errors. statusCode = %s", response.getStatus()),
               readValue(response.getBody().getObject().get(VALIDATIONS_KEY).toString(),
                       new TypeReference<List<ValidationErrorDto>>() {
                       }));
   }

   private <T> List<T> readValue(String resultAsString, TypeReference<List<T>> valueTypeRef) {
       List<T> list;
       try {
           list = objectMapper.readValue(resultAsString, valueTypeRef);
       } catch (IOException e) {
           throw new FlightClientException("Object Mapping failure.", e);
       }
       return list;
   }
}
kung saan ang FlightClientException ay ganito ang hitsura:
import com.github.romankh3.flightsmonitoring.client.dto.ValidationErrorDto;
import java.util.List;

/**
* A {@link RuntimeException} that is thrown in case of an flight monitoring failures.
*/
public final class FlightClientException extends RuntimeException {

   public FlightClientException(String message) {
       super(message);
   }

   public FlightClientException(String message, Throwable throwable) {
       super(message, throwable);
   }

   public FlightClientException(String message, List<ValidationErrorDto> errors) {
       super(message);
       this.validationErrorDtos = errors;
   }

   private List<ValidationErrorDto> validationErrorDtos;
}
Bilang resulta, ayon sa data mula sa PlacesCl
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION