JavaRush /Java Blogu /Random-AZ /Aviabiletlərin qiymətinə nəzarət sisteminin yaradılması: ...
Roman Beekeeper
Səviyyə

Aviabiletlərin qiymətinə nəzarət sisteminin yaradılması: addım-addım təlimat [1-ci hissə]

Qrupda dərc edilmişdir

Məzmun:

Aviabiletlərin qiymətlərinin monitorinqi sisteminin yaradılması: addım-addım təlimat [1-ci hissə] - 1Hamıya salam, JavaRush icması! Bu gün biz addım-addım aviabilet qiymətlərini izləmək üçün Spring Boot tətbiqini necə yazmaq barədə danışacağıq. Məqalə aşağıdakılar haqqında fikri olan insanlar üçün nəzərdə tutulub:
  • REST və REST son nöqtələrinin necə qurulduğu;
  • əlaqəli verilənlər bazası;
  • maven işi (xüsusən də asılılıq nədir);
  • JSON obyekti;
  • giriş prinsipləri.
Gözlənilən Davranış:
  1. Siz müəyyən bir tarix üçün uçuş seçə və onun qiymətini izləyə bilərsiniz. İstifadəçi e-poçt ünvanı ilə müəyyən edilir. Qiymət dəyişikliyinə abunə olan kimi istifadəçi elektron poçtla bildiriş alır.
  2. Hər 30 dəqiqədən bir (bu interval application.properties vasitəsilə konfiqurasiya edilir) bütün abunəliklər üçün uçuş üçün minimum qiymət yenidən hesablanır. Dəyərlərdən biri aşağı düşərsə, istifadəçi e-poçtla bildiriş alacaq.
  3. Köhnə uçuş tarixi olan bütün abunəliklər silinəcək.
  4. REST API vasitəsilə siz:
    • abunə yaratmaq;
    • redaktə etmək;
    • bütün abunələri e-poçtla almaq;
    • abunəni silin.

Məqsədə çatmaq üçün fəaliyyət planı

Uçuşlar haqqında məlumatı haradansa götürmək lazım olduğundan başlamaq lazımdır. Tipik olaraq, veb saytlar məlumatın əldə edilə biləcəyi açıq REST API təmin edir.

API (tətbiq proqramlaşdırma interfeysi) proqramla qarşılıqlı əlaqə qura biləcəyiniz bir interfeysdir. Bundan biz REST API-nin nə olduğuna körpü qura bilərik.

REST API veb tətbiqi ilə əlaqə saxlamaq üçün istifadə edilə bilən REST sorğularının interfeysidir.

Bunun üçün biz Skyscanner , daha doğrusu API-dən istifadə edəcəyik ( Rakuten API veb saytında ). Sonra, əsas təməl kimi düzgün çərçivəni seçməlisiniz. Ən populyar və tələb olunan Bahar ekosistemi və onların yaradılmasının tacıdır - Spring Boot. Onların rəsmi saytına daxil ola bilərsiniz və ya Habré-dəki məqaləni oxuya bilərsiniz . İstifadəçi abunəliklərini saxlamaq üçün biz daxili H2 verilənlər bazasından istifadə edəcəyik . JSON-dan dərslərə və geri oxumaq üçün biz Jackson Layihəsindən istifadə edəcəyik ( burada resursumuzdakı keçid var ). Biz istifadəçilərə mesaj göndərmək üçün spring-boot-starter-mail-dən istifadə edəcəyik.Tətbiqin müəyyən bir tezlikdə minimum qiyməti yenidən hesablaması üçün Spring Scheduler-dən istifadə edəcəyik . REST API yaratmaq üçün biz spring-boot-starter-web istifadə edəcəyik . Borc kodunu yazmamaq üçün (alıcılar, təyinedicilər, əvəzedici bərabərliklər və hashcode, obyektlər üçün toString()) biz Project Lombok istifadə edəcəyik . REST API-ni hiss etmək və görmək üçün biz real vaxt rejimində izləmə üçün Swagger 2 və dərhal Swagger UI-dən (istifadəçi interfeysi) istifadə edəcəyik. İndi göründüyü kimi: Aviabiletlərin qiymətinə nəzarət sisteminin yaradılması: addım-addım təlimat [1-ci hissə] - 2abunəliklərin yaradılması, redaktə edilməsi, əldə edilməsi və silinməsinə uyğun gələn 4 istirahət sorğusu var.

Skyscanner API-ni araşdırın

Rakuten api -yə keçidi izləyək . Əvvəlcə qeydiyyatdan keçməlisiniz.Bütün Aviabiletlərin qiymətinə nəzarət sisteminin yaradılması: addım-addım təlimat [1-ci hissə] - 3bunlar onların saytından istifadə etmək və orada yerləşdirilən ictimai API-lərə sorğu göndərmək üçün unikal açar əldə etmək üçün lazımdır. Bu API-lərdən biri bizə lazım olan Skyscanner Uçuş Axtarışıdır . İndi bunun necə işlədiyini anlayaq. Gəlin GET List Places sorğusunu tapaq. Şəkil göstərir ki, məlumatları doldurmalı və Test Son nöqtəsini işə salmalısınız , bunun nəticəsində sağda JSON obyekti şəklində cavab alırıq: Aviabiletlərin qiymətlərinə nəzarət sisteminin yaradılması: addım-addım təlimat [1-ci hissə] - 4və sorğu belə yaradılacaq:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
və bütün parametrlər bu düsturla əvəz olunacaq, biz əldə edirik:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
və bu sorğulara iki başlıq ötürüləcək:

.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
qeydiyyatdan keçdikdən sonra harada sign-up-for-keyverilir. Qiymət enişini izləmək üçün bizə Sitatları nəzərdən keçirin son nöqtəsi lazımdır . Özünüz tapın :)

Spring Boot əsasında proqram çərçivəsinin yaradılması

Spring Boot ilə tez və asanlıqla layihə yaratmaq üçün Spring Initializr istifadə edə bilərsiniz . Aşağıdakı seçimləri seçin:
  1. Maven layihəsi
  2. Java
  3. 2.1.10
  4. qrup - hansını zəruri hesab edirsinizsə, məsələn ru.javarush
  5. artefakt - tamamilə eyni, məsələn, uçuşlara nəzarət
  6. asılılıq axtarışında aşağıdakıları axtarırıq:
    • Bahar Veb
    • Java poçt göndərən
    • Spring Data Jpa
    • H2 verilənlər bazası
Və sonra Yarat klikləyin . Budur: bitmiş layihə arxiv kimi yüklənəcək. Bir şey alınmazsa, istədiyiniz layihəni saxladığım linkdən istifadə edə bilərsiniz . Əlbəttə ki, bunu özünüz etmək və necə işlədiyini başa düşmək daha yaxşıdır. Tətbiq üç təbəqədən ibarət olacaq:
  • CONTROLLER - proqrama daxil olun. REST API burada təsvir olunacaq
  • XİDMƏT biznes məntiqi təbəqəsidir. Tətbiqin bütün məntiqi burada təsvir olunacaq.
  • REPOZİTORİYA - verilənlər bazası ilə işləmək üçün təbəqə.
Həmçinin, Skyscanner Flight Search API üçün müştəri ilə əlaqəli siniflər ayrıca paket olacaq.

Layihədə Skyscanner Flight Search API-ə sorğular üçün müştəri yazırıq

Skyscanner lütfən onların API-dən necə istifadə olunacağına dair məqalə təqdim etdi (biz aktiv sorğu ilə sessiya yaratmayacağıq). “Müştəri yazmaq” nə deməkdir? Müəyyən parametrləri olan xüsusi URL-ə sorğu yaratmalı və bizə geri ötürülən məlumatlar üçün DTO (məlumat ötürmə obyekti) hazırlamalıyıq. Saytda dörd sorğu qrupu var:
  1. Canlı Uçuş Axtarışı - hazırda bunu lazımsız hesab etməyəcəyik.
  2. Yerlər - yazaq.
  3. Uçuş qiymətlərini nəzərdən keçirin - biz bütün məlumatları əldə edə biləcəyiniz bir sorğudan istifadə edəcəyik.
  4. Lokallaşdırma - onu əlavə edək ki, hansı məlumatların dəstəkləndiyini bilək.

Lokallaşdırma sorğusu üçün müştəri xidməti yaradın:

Plan buxarlanmış şalgam kimi sadədir: sorğu yaradın, parametrlərə baxın, cavaba baxın. İki sorğu var: Siyahı markerləri və Valyutalar. Valyutalardan başlayaq. Şəkil göstərir ki, bu, əlavə sahələri olmayan sorğudur: dəstəklənən valyutalar haqqında məlumat əldə etmək lazımdır: Aviabiletlərin qiymətinə nəzarət sisteminin yaradılması: addım-addım təlimat [1-ci hissə] - 6Cavab eyni obyektlərin kolleksiyasını ehtiva edən JSON obyekti formasındadır, məsələn:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Bu obyekt üçün CurrencyDto yaradaq:
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;
}
Harada:
  • @Data Lombok layihəsinin annotasiyasıdır və bütün alıcıları, təyinçiləri, toString(), equals() və hashCode() metodlarını ləğv edir. Kodun oxunuşunu yaxşılaşdıran və POJO obyektlərinin yazılma vaxtını sürətləndirən ;
  • @JsonProperty("Kod") bu dəyişənə hansı sahənin təyin ediləcəyini bildirən Cekson Layihəsindən annotasiyadır. Yəni JSON-da Koda bərabər sahə kod dəyişəninə təyin ediləcək .
Skyscanner-in rəsmi məqaləsi REST sorğuları üçün UniRest kitabxanasından istifadə etməyi təklif edir . Buna görə də REST vasitəsilə sorğuları həyata keçirəcək başqa bir xidmət yazacağıq. Bu UniRestService olacaq . Bunu etmək üçün maven-ə yeni bir asılılıq əlavə edin:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Sonra REST sorğularını yerinə yetirəcək bir xidmət yazacağıq. Əlbəttə ki, hər bir müştəri/xidmət üçün interfeys və onun həyata keçirilməsini yaradacağıq:
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);

}
Və onun həyata keçirilməsi:
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;
   }
}
Onun mahiyyəti ondan ibarətdir ki, bizi maraqlandıran bütün sorğular GET sorğuları üçün yaradılır və bu xidmət hazır sorğunu qəbul edir və aşağıdakı kimi lazımi başlıqları əlavə edir:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Xüsusiyyətlərdən məlumat almaq üçün aşağıda göstərildiyi kimi @Value annotasiyasından istifadə edin:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Bildirir ki, application.properties-də x.rapid.api.key adlı bir xüsusiyyət olacaq və bu dəyişənə daxil edilməlidir. Sərt kodlanmış dəyərlərdən xilas oluruq və bu dəyişənin tərifini proqram kodundan əldə edirik. Üstəlik, bu proqramı GitHub-da dərc edərkən bu əmlakın dəyərini əlavə etmirəm. Bu təhlükəsizlik səbəbi ilə edilir. REST sorğuları ilə işləyəcək bir xidmət yazdıq, indi Lokallaşdırma xidmətinin vaxtıdır. Biz OOP əsasında proqram qururuq, ona görə də LocalizationClient interfeysini və onun tətbiqini LocalisationClientImpl yaradırıq :
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();

}
və LocalisationClientImpl tətbiqi
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>>() {
       });
   }
}
Harada
  • @Autowired annotasiyadır ki, bu sinifə obyekt yeritmək və onu yaratmadan, yəni yeni Obyekt əməliyyatı olmadan istifadə etmək lazımdır;
  • @Component bu obyektin Tətbiq Kontekstinə əlavə edilməli olduğunu bildirən annotasiyadır ki, sonradan @Autowired annotasiyasından istifadə edilərək yeridilə bilsin;
  • ObjectMapper objectMapper bütün bunları Java obyektlərinə çevirən Jackson Layihəsinin obyektidir.
  • CurrencyDTO və 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;
}
Layihənin hər hansı bir hissəsinə ObjectMapper yeritmək üçün mən konfiqurasiya sinfi vasitəsilə onun yaradılması və ApplicationContext-ə əlavə edilməsini əlavə etdim.
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;
   }
}
@Configuration annotasiyası Bahara bu sinifdə bəzi konfiqurasiyaların olacağını bildirir. Və yalnız bunun üçün ObjectMapper əlavə etdim. Eynilə, biz PlacesClient və PlacesClientImpl əlavə edirik:
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;
}
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>>() {
       });
   }
}
PlacesDto formasının olduğu yer:
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;
}
Və nəhayət, lazımi məlumatlara əsaslanaraq, uçuş üçün minimum qiyməti və bütün lazımi məlumatları qaytaracaq müştəri xidməti: FlightPriceClient və FlightPriceClientImpl. Biz yalnız bir sorğu həyata keçirəcəyik, 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;
   }
}
FlightClientException harada görünür:
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;
}
Nəticədə, PlacesCl məlumatlarına görə
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION