JavaRush /Java блогу /Random-KY /Авиа билеттерине баа мониторинг системасын түзүү: кадам-к...
Roman Beekeeper
Деңгээл

Авиа билеттерине баа мониторинг системасын түзүү: кадам-кадам колдонмо [1-бөлүк]

Группада жарыяланган

Мазмуну:

Авиабилеттердин баасына мониторинг жүргүзүү системасын түзүү: кадамдык колдонмо [1-бөлүк] - 1Баарына салам, JavaRush коомчулугу! Бүгүн биз этап-этабы менен авиа билеттеринин баасын көзөмөлдөө үчүн Spring Boot тиркемесин кантип жазуу керектиги жөнүндө сүйлөшөбүз. Макала төмөнкүлөр жөнүндө түшүнүгү бар адамдар үчүн арналган:
  • REST жана REST акыркы чекиттери кантип курулат;
  • реляциялык маалымат базалары;
  • мавендин иши (атап айтканда, көз карандылык деген эмне);
  • JSON an objectи;
  • каттоо принциптери.
Күтүлгөн жүрүм-турум:
  1. Сиз белгилүү бир датага рейсти тандап, анын баасын көзөмөлдөй аласыз. Колдонуучу электрондук почта дареги менен аныкталат. Бааны өзгөртүүгө жазылуу жасалганда, колдонуучу электрондук почта аркылуу билдирүү алат.
  2. Ар бир 30 мүнөт сайын (бул интервал application.properties аркылуу конфигурацияланат) бардык жазылуулар үчүн рейстин минималдуу баасы кайра эсептелет. Эгерде баалуулуктардын бири төмөндөп кетсе, колдонуучу электрондук почта аркылуу эскертме алат.
  3. Учуу күнү эскирген бардык жазылуулар жок кылынат.
  4. REST API аркылуу сиз:
    • жазылуу түзүү;
    • түзөтүү;
    • электрондук почта аркылуу бардык жазылууларды алуу;
    • жазылууну жок кылуу.

Максатка жетүү үчүн иш-аракеттер планы

Сиз учуу жөнүндө маалыматты бир жерден алуу керек экенин менен баштоо керек. Адатта, веб-сайттар маалыматты алуу үчүн ачык REST API менен камсыз кылат.

API (applications программалоо интерфейси) - бул колдонмо менен өз ара аракеттене турган интерфейс. Мындан биз REST API дегенге көпүрө кура алабыз.

REST API бул веб-тиркеме менен байланышуу үчүн колдонула турган REST сурамдарынын интерфейси.

Бул үчүн, биз Skyscanner колдонобуз , тагыраак айтканда, API ( Rakuten API веб-сайтында ). Андан кийин, сиз негизги негиз катары туура алHowты тандоо керек. Эң популярдуу жана талап кылынган жазгы экосистема жана алардын жаралышынын таажы - Жазгы Бут. Сиз алардын расмий сайтына бара аласыз, же Habré боюнча макаланы окуй аласыз . Колдонуучунун жазылууларын сактоо үчүн биз орнотулган H2 маалымат базасын колдонобуз . JSONдан класстарга жана кайра окуу үчүн биз Джексон долбоорун колдонобуз ( бул жерде биздин ресурсубуздагы шилтеме ). Биз колдонуучуларга билдирүүлөрдү жөнөтүү үчүн spring-boot-starter-mail колдонобуз .. Колдонмо берилген жыштыктагы минималдуу бааны кайра эсептөө үчүн, биз Жазгы Пландаштыруучу колдонобуз . REST API түзүү үчүн биз spring-boot-starter-web колдонобуз . Карызга алынган codeду жазбаш үчүн (алуучу, орнотуучу, жокко чыгаруу эквиваленти жана хэшcode, an objectтер үчүн 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 an objectиси түрүндө жооп алабыз: Авиабилеттердин баасына мониторинг жүргүзүү системасын түзүү: кадамдык колдонмо [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 Initializr колдоно аласыз . Төмөнкү опцияларды тандаңыз:
  1. Maven долбоору
  2. Java
  3. 2.1.10
  4. топ - кайсынысын керек деп ойлосоңуз, мисалы ru.javarush
  5. артефакт - дал ушундай, мисалы, учуу-мониторинг
  6. көз карандылыкты издөөдө биз төмөнкүлөрдү издейбиз:
    • Жазгы веб
    • Java почта жөнөтүүчү
    • Жазгы маалыматтар Jpa
    • H2 маалымат базасы
Анан түзүү чыкылдатыңыз . Болду: даяр долбоор архив катары жүктөлөт. Эгер бир нерсе иштебей калса, мен каалаган долбоорду сактаган шилтемени колдонсоңуз болот . Албетте, муну өзүңүз жасап, анын кантип иштээрин түшүнгөнүңүз жакшы. Колдонмо үч катмардан турат:
  • CONTROLLER - тиркемеге кирүү. REST API бул жерде сүрөттөлөт
  • SERVICE – бул бизнес-логикалык катмар. Колдонмонун бүт логикасы бул жерде сүрөттөлөт.
  • РЕПОЗИТОРИЯ – маалымат базасы менен иштөө үчүн катмар.
Ошондой эле, Skyscanner Flight Search API үчүн кардар менен байланышкан класстар өзүнчө пакет болот.

Биз долбоордо Skyscanner Flight Search API'ге суроо-талаптар үчүн кардар жазып жатабыз

Skyscanner алардын API'син кантип колдонуу керектиги жөнүндө макала берди (биз активдүү сурам менен сессияны түзбөйбүз). "Кардар жазуу" деген эмнени билдирет? Биз белгилүү бир параметрлери бар белгилүү бир URL дарегине суроо-талапты түзүп, бизге кайра өткөрүлүп берилген маалыматтар үчүн DTO (маалыматтарды өткөрүү an objectисин) даярдашыбыз керек. Сайтта сурамдардын төрт тобу бар:
  1. Live Flight Search - биз аны учурда керексиз деп эсептебейбиз.
  2. Орундар - жазабыз.
  3. Учуулардын баасын карап чыгуу - биз бардык маалыматты ала турган бир суроону колдонобуз.
  4. Локалдаштыруу - келгиле, кайсы маалыматтар колдоого алынарын билүү үчүн аны кошолу.

Локалдаштыруу сурамы үчүн кардар кызматын түзүү:

План бууланган шалкан сыяктуу жөнөкөй: суроо-талапты түзүңүз, параметрлерди көрүңүз, жоопту көрүңүз. Эки суроо бар: Тизме маркерлери жана Валюталар. Валюталардан баштайлы. Сүрөт бул кошумча талаалары жок өтүнүч экенин көрсөтүп турат: ал колдоого алынган валюталар жөнүндө маалымат алуу үчүн керек: Авиабилеттердин баасына мониторинг системасын түзүү: кадамдык колдонмо [1-бөлүк] - 6Жооп JSON an objectисинин түрүндө, ал ошол эле an objectтердин жыйнагын камтыйт, мисалы:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Бул an object үчүн 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 an objectилерин жазуу убактысын тездетет ;
  • @JsonProperty("Код") бул өзгөрмөгө кайсы талаа ыйгарыларын айткан Джексон долбоорунун annotationсы. Башкача айтканда, JSONдагы Code'ге барабар талаа code өзгөрмөсүнө дайындалат .
Skyscannerдин расмий макаласы UniRest китепканасын REST сурамдары үчүн колдонууну сунуштайт . Ошондуктан, биз 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();

}
жана 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>>() {
       });
   }
}
Кайда
  • @Autowired - бул класска an objectти сайып, аны түзбөстөн, башкача айтканда, жаңы Object операциясысыз колдонуу керектиги жөнүндө annotation;
  • @Component - бул an object кийинчерээк @Autowired annotationсын колдонуу менен киргизүү үчүн Колдонмо контекстине кошулушу керек деген annotation;
  • ObjectMapper objectMapper – бул Джексон долбоорунун an objectиси, ал мунун баарын Java an objectтерине которгон.
  • 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;
}
ОбъектМапперди долбоордун каалаган бөлүгүнө киргизүү үчүн мен аны конфигурация классы аркылуу 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