JavaRush /Java блогы /Random-KK /Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық н...
Roman Beekeeper
Деңгей

Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық нұсқаулық [1 бөлім]

Топта жарияланған

Мазмұны:

Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық нұсқаулық [1-бөлім] - 1Барлығына сәлем, JavaRush қауымдастығы! Бүгін біз әуе билеттерінің бағасын кезең-кезеңімен бақылау үшін Spring Boot қосымшасын қалай жазу керектігі туралы сөйлесеміз. Мақала мыналар туралы түсінігі бар адамдарға арналған:
  • REST және REST соңғы нүктелері қалай құрастырылады;
  • реляциялық мәліметтер базасы;
  • мавен жұмысы (атап айтқанда, тәуелділік дегеніміз не);
  • JSON нысаны;
  • тіркеу принциптері.
Күтілетін мінез-құлық:
  1. Сіз белгілі бір күнге рейсті таңдап, оның бағасын бақылай аласыз. Пайдаланушы электрондық пошта мекенжайы арқылы анықталады. Бағаның өзгеруіне жазылу жасалғаннан кейін пайдаланушы электрондық пошта арқылы хабарлама алады.
  2. Әрбір 30 minutes сайын (бұл аралық application.properties арқылы конфигурацияланады) рейстің ең төменгі бағасы барлық жазылымдар үшін қайта есептеледі. Егер мәндердің бірі төмендесе, пайдаланушы электрондық пошта арқылы хабарлама алады.
  3. Ұшу күні ескірген барлық жазылымдар жойылады.
  4. REST API арқылы сіз:
    • жазылым жасау;
    • өңдеу;
    • электрондық пошта арқылы барлық жазылымдарды алу;
    • жазылымды жою.

Мақсатқа жету үшін әрекет жоспары

Ұшу туралы ақпаратты бір жерден алу керек екенінен бастау керек. Әдетте, веб-сайттар ақпаратты шығарып алуға болатын ашық REST API ұсынады.

API (бағдарламалық бағдарламалау интерфейсі) - бұл қолданбамен өзара әрекеттесуге болатын интерфейс. Осыдан біз REST API дегенге көпір құра аламыз.

REST API веб-бағдарламамен байланысу үшін пайдаланылуы мүмкін REST сұрауларының интерфейсі болып табылады.

Ол үшін Skyscanner , дәлірек айтқанда, API ( Rakuten API веб-сайтында) қолданамыз . Әрі қарай, негізгі іргетас ретінде дұрыс негізді таңдау керек. Ең танымал және сұранысқа ие көктемгі экожүйе және олардың жасалу тәжі - Spring Boot. Сіз олардың ресми веб-сайтына кіре аласыз немесе Habré туралы мақаланы оқи аласыз . Пайдаланушы жазылымдарын сақтау үшін біз кірістірілген H2 дерекқорын қолданамыз . JSON-дан сыныптарға және кері оқу үшін біз Джексон жобасын пайдаланамыз ( міне, біздің ресурстағы сілтеме ). Біз пайдаланушыларға хабарламалар жіберу үшін spring-boot-starter-mail-ді қолданамыз.Қолданбаның берілген жиіліктегі ең төменгі бағаны қайта есептеуі үшін біз Spring Scheduler пайдаланамыз . REST API жасау үшін біз spring-boot-starter-web пайдаланамыз . Қарызға алынған codeты жазбау үшін (алғыштар, орнатушылар, қайта анықтау теңдеулері және хэшcode, нысандар үшін toString()) біз Project Lombok қолданамыз . REST API интерфейсін сезіну және көру үшін біз нақты уақыттағы бақылау үшін Swagger 2 және бірден Swagger UI (пайдаланушы интерфейсі) қолданамыз. Енді ол келесідей: Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық нұсқаулық [1-бөлім] - 2жазылымдарды жасауға, өңдеуге, алуға және жоюға сәйкес келетін 4 демалыс сұрауы бар.

Skyscanner API шолу

rakuten api сілтемесіне өтейік . Алдымен тіркелу қажет.Мұның Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық нұсқаулық [1-бөлім] - 3барлығы сайтты пайдалану үшін бірегей кілтті алу және онда жарияланған жалпы API интерфейстеріне сұрау салу үшін қажет. Осы API интерфейстерінің бірі бізге қажет Skyscanner Flight Search болып табылады . Енді оның қалай жұмыс істейтінін анықтайық. GET List Places сұрауын табайық. Суретте деректерді толтырып, Test Endpoint бағдарламасын бастау керек екендігі көрсетілген , нәтижесінде оң жақта JSON нысаны түрінде жауап аламыз: Әуе билеттерінің бағасын бақылау жүйесін құру: қадамдық нұсқаулық [1 бөлім] - 4және сұрау келесідей жасалады:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
және барлық параметрлер осы формулаға ауыстырылады, біз аламыз:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
және екі тақырып осы сұрауларға жіберіледі:

.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
тіркеуден кейін қай жерде sign-up-for-keyберіледі. Бағаның құлдырауын бақылау үшін бізге Баға ұсыныстарын шолу соңғы нүктесі қажет болады. Оны өзіңіз табыңыз :)

Spring Boot негізінде қолданбалы жүйені құру

Spring Boot көмегімен жобаны жылдам және оңай жасау үшін Spring Initializr пайдалана аласыз . Келесі опцияларды таңдаңыз:
  1. Maven жобасы
  2. Java
  3. 2.1.10
  4. топ - қайсысы қажет деп ойласаңыз, мысалы ru.javarush
  5. артефакт - дәл солай, мысалы, ұшу-мониторинг
  6. тәуелділікті іздеуде біз мыналарды іздейміз:
    • Көктем торабы
    • Java пошта жіберушісі
    • Көктемгі деректер Jpa
    • H2 деректер базасы
Содан кейін Жасау түймесін басыңыз . Міне, дайын жоба мұрағат ретінде жүктеледі. Егер бірдеңе орындалмаса, мен қалаған жобаны сақтаған сілтемені пайдалануға болады . Әрине, мұны өзіңіз жасау және оның қалай жұмыс істейтінін түсіну жақсы. Қолданба үш қабаттан тұрады:
  • CONTROLLER - қолданбаға кіру. REST API осы жерде сипатталатын болады
  • ҚЫЗМЕТ — іскери логикалық деңгей. Қолданбаның бүкіл логикасы осы жерде сипатталады.
  • РЕПОЗИТОРИЯ – мәліметтер қорымен жұмыс істеуге арналған қабат.
Сондай-ақ Skyscanner Flight Search API үшін клиентке қатысты сыныптар бөлек пакет болады.

Біз жобадағы Skyscanner Flight Search API сұрауларына клиент жазып жатырмыз

Skyscanner олардың API пайдалану жолы туралы мақаланы ұсынды (біз белсенді сұраумен сеанс жасамаймыз). «Клиент жазу» деген нені білдіреді? Бізге белгілі бір параметрлері бар белгілі бір URL мекенжайына сұрау жасау керек және бізге кері тасымалданатын деректер үшін DTO (деректерді тасымалдау нысаны) дайындау керек. Сайтта сұраулардың төрт тобы бар:
  1. Тікелей ұшуды іздеу - біз оны қазір қажетсіз деп санамаймыз.
  2. Орындар - жазайық.
  3. Ұшу бағасын шолу - біз барлық ақпаратты алуға болатын бір сұрауды қолданамыз.
  4. Локализация - қандай деректерге қолдау көрсетілетінін білу үшін оны қосайық.

Локализация сұрауы үшін клиенттік қызметті жасаңыз:

Жоспар буға пісірілген репа сияқты қарапайым: сұраныс жасаңыз, параметрлерді қараңыз, жауапты қараңыз. Екі сұрау бар: Тізім маркерлері және Валюталар. Валюталардан бастайық. Суретте бұл қосымша өрістері жоқ сұрау екенін көрсетеді: ол қолдау көрсетілетін валюталар туралы ақпаратты алу үшін қажет: Creation системы мониторинга цен на авиабилеты: пошаговое руководство [Часть 1] - 6Жауап JSON нысаны түрінде болады, ол бірдей нысандар жиынтығын қамтиды, мысалы:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Осы нысан үшін CurrencyDto жасайық:
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;
}
Қайда:
  • @Data — Lombok жобасының annotationсы және барлық алушыларды, орнатушыларды, toString(), equals() және hashCode() әдістерін қайта анықтауды жасайды. Кодтың оқылуын жақсартатын және POJO нысандарын жазу уақытын тездететін нәрсе ;
  • @JsonProperty("Код") - бұл айнымалы мәнге қандай өріс тағайындалатынын көрсететін Джексон жобасының annotationсы. Яғни, code айнымалы мәніне JSON ішіндегі codeқа тең өріс тағайындалады .
Skyscanner ресми мақаласы REST сұраулары үшін UniRest кітапханасын пайдалануды ұсынады . Сондықтан біз REST арқылы сұрауларды орындайтын басқа қызметті жазамыз. Бұл UniRestService болады . Мұны істеу үшін maven-ге жаңа тәуелділікті қосыңыз:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Содан кейін біз REST сұрауларын орындайтын қызметті жазамыз. Әрине, әрбір клиент/қызмет үшін интерфейсті және оны іске асыруды жасаймыз:
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);

}
Және оны жүзеге асыру:
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;
   }
}
Оның мәні бізді қызықтыратын барлық сұраулар GET сұраулары үшін жасалған және бұл қызмет дайын сұранысты қабылдайды және келесідей қажетті тақырыптарды қосады:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Сипаттардан деректерді алу үшін төменде көрсетілгендей @Value annotationсын пайдаланыңыз:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Ол application.properties ішінде x.rapid.api.key деп аталатын сипат болатынын айтады, оны осы айнымалыға енгізу керек. Біз қатты codeталған мәндерден құтыламыз және осы айнымалының анықтамасын бағдарлама codeынан аламыз. Сонымен қатар, мен бұл қолданбаны GitHub сайтында жариялаған кезде мен бұл сипаттың мәнін қоспаймын. Бұл қауіпсіздік мақсатында жасалады. Біз REST сұрауларымен жұмыс істейтін қызметті жаздық, енді локализация қызметінің уақыты келді. Біз OOP негізіндегі қосымшаны жасап жатырмыз, сондықтан LocalizationClient интерфейсін және оны 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();

}
және LocalisationClientImpl енгізу
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>>() {
       });
   }
}
Қайда
  • @Autowired - бұл классқа нысанды енгізу және оны жасамай, яғни жаңа Object операциясынсыз пайдалану керектігін айтатын annotation;
  • @Component - бұл нысанды кейінірек @Autowired annotationсының көмегімен енгізуге болатындай етіп Қолданба мәтінмәніне қосу керектігін айтатын annotation;
  • ObjectMapper objectMapper — осының барлығын Java нысандарына аударатын Джексон жобасының нысаны.
  • CurrencyDTO және 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;
}
Жобаның кез келген бөлігіне ObjectMapper енгізу үшін мен конфигурация сыныбы арқылы оны ApplicationContext құруды және қосуды қостым.
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 annotationсы көктемге осы сыныпта кейбір конфигурациялар болатынын айтады. Бұл үшін мен ObjectMapper қостым. Сол сияқты, біз PlacesClient және 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;
}
және
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 пішіні бар:
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;
}
Ақырында, қажетті деректер негізінде рейстің ең төменгі бағасын және барлық қажетті ақпаратты қайтаратын клиенттік қызмет: FlightPriceClient және FlightPriceClientImpl. Біз тек бір сұрауды орындаймыз, 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 келесідей көрінеді:
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;
}
Нәтижесінде, PlacesCl деректеріне сәйкес
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION