JavaRush /Blog Java /Random-MS /Mencipta sistem pemantauan harga tiket penerbangan: pandu...

Mencipta sistem pemantauan harga tiket penerbangan: panduan langkah demi langkah [Bahagian 1]

Diterbitkan dalam kumpulan

Kandungan:

Mencipta sistem untuk memantau harga tiket penerbangan: panduan langkah demi langkah [Bahagian 1] - 1Hello semua, komuniti JavaRush! Hari ini kita akan bercakap tentang cara menulis aplikasi Spring Boot untuk memantau harga tiket penerbangan langkah demi langkah. Artikel ini bertujuan untuk orang yang mempunyai idea tentang:
  • REST dan cara titik akhir REST dibina;
  • pangkalan data hubungan;
  • kerja maven (khususnya, apakah pergantungan);
  • objek JSON;
  • prinsip pembalakan.
Tingkah Laku yang Dijangka:
  1. Anda boleh memilih penerbangan untuk tarikh tertentu dan menjejaki harga untuk penerbangan itu. Pengguna dikenal pasti melalui alamat e-mel. Sebaik sahaja langganan kepada perubahan harga dibuat, pengguna menerima pemberitahuan melalui e-mel.
  2. Setiap 30 minit (selang ini dikonfigurasikan melalui application.properties) harga minimum untuk penerbangan dikira semula untuk semua langganan. Jika salah satu nilai telah menjadi lebih rendah, pengguna akan menerima pemberitahuan melalui e-mel.
  3. Semua langganan dengan tarikh penerbangan yang lapuk akan dipadamkan.
  4. Melalui REST API anda boleh:
    • buat langganan;
    • edit;
    • terima semua langganan melalui e-mel;
    • memadam langganan.

Pelan tindakan untuk mencapai matlamat

Anda perlu bermula dengan fakta bahawa maklumat tentang penerbangan perlu diambil dari suatu tempat. Lazimnya, tapak web menyediakan API REST terbuka yang melaluinya maklumat boleh diambil semula.

API (antara muka pengaturcaraan aplikasi) ialah antara muka di mana anda boleh berinteraksi dengan aplikasi. Daripada ini kita boleh membina jambatan kepada apa itu REST API.

API REST ialah antara muka permintaan REST yang boleh digunakan untuk berkomunikasi dengan aplikasi web.

Untuk melakukan ini, kami akan menggunakan Skyscanner , atau lebih tepat lagi, API (di tapak web API Rakuten ). Seterusnya, anda perlu memilih rangka kerja yang betul sebagai asas asas. Yang paling popular dan dalam permintaan ialah ekosistem Spring dan mahkota ciptaan mereka - Spring Boot. Anda boleh pergi ke laman web rasmi mereka, atau anda boleh membaca artikel di Habré . Untuk menyimpan langganan pengguna, kami akan menggunakan pangkalan data H2 terbina dalam . Untuk membaca dari JSON ke kelas dan kembali, kami akan menggunakan Projek Jackson ( di sini ialah pautan pada sumber kami ). Kami akan menggunakan spring-boot-starter-mail untuk menghantar mesej kepada pengguna . Untuk aplikasi mengira semula harga minimum pada kekerapan tertentu, kami akan menggunakan Spring Scheduler . Untuk membuat API REST kami akan menggunakan spring-boot-starter-web . Untuk tidak menulis kod yang dipinjam (getters, setter, override equals dan hashcode, toString() untuk objek), kami akan menggunakan Project Lombok . Untuk merasai dan melihat API REST, kami akan menggunakan Swagger 2 dan serta-merta Swagger UI (antara muka pengguna) untuk penjejakan masa nyata. Begini rupanya sekarang: Mencipta sistem pemantauan harga tiket udara: panduan langkah demi langkah [Bahagian 1] - 2di mana terdapat 4 pertanyaan selebihnya yang sepadan dengan membuat, mengedit, mendapatkan dan memadamkan langganan.

Meneroka API Skyscanner

Jom ikuti pautan ke rakuten api . Mula-mula anda perlu mendaftar. Mencipta sistem pemantauan harga tiket udara: panduan langkah demi langkah [Bahagian 1] - 3Semua ini diperlukan untuk menerima kunci unik untuk menggunakan tapak mereka dan membuat permintaan kepada API awam yang disiarkan padanya. Salah satu API ini ialah Carian Penerbangan Skyscanner yang kami perlukan . Sekarang mari kita fikirkan bagaimana ia berfungsi. Mari cari permintaan GET List Places. Gambar menunjukkan bahawa anda perlu mengisi data dan memulakan Test Endpoint , akibatnya kami menerima respons dalam bentuk objek JSON di sebelah kanan: Mencipta sistem untuk memantau harga tiket penerbangan: panduan langkah demi langkah [Bahagian 1] - 4dan permintaan akan dibuat seperti ini:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
dan semua parameter akan digantikan ke dalam formula ini, kita dapat:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
dan dua tajuk akan dihantar kepada permintaan ini:

.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
di mana sign-up-for-keyia dikeluarkan selepas pendaftaran. Untuk menjejaki penurunan harga, kami memerlukan titik akhir Semak Imbas Sebutharga . Cari sendiri :)

Mencipta rangka kerja aplikasi berdasarkan Spring Boot

Untuk membuat projek dengan cepat dan mudah dengan Spring Boot, anda boleh menggunakan Spring Initializr . Pilih pilihan berikut:
  1. Projek Maven
  2. Jawa
  3. 2.1.10
  4. kumpulan - mana-mana yang anda fikir perlu, contohnya ru.javarush
  5. artifak - betul-betul sama, contohnya pemantauan penerbangan
  6. dalam carian pergantungan kami mencari yang berikut:
    • Web Spring
    • Penghantar Mel Java
    • Spring Data Jpa
    • Pangkalan Data H2
Dan kemudian klik Jana . Itu sahaja: projek siap akan dimuat turun sebagai arkib. Jika sesuatu tidak berjaya, anda boleh menggunakan pautan tempat saya menyimpan projek yang diingini . Sudah tentu, lebih baik melakukan ini sendiri dan memahami cara ia berfungsi. Aplikasi ini akan terdiri daripada tiga lapisan:
  • PENGAWAL - log masuk ke aplikasi. API REST akan diterangkan di sini
  • SERVICE ialah lapisan logik perniagaan. Keseluruhan logik aplikasi akan diterangkan di sini.
  • REPOSITORY - lapisan untuk bekerja dengan pangkalan data.
Selain itu, kelas yang berkaitan dengan pelanggan untuk API Carian Penerbangan Skyscanner akan menjadi pakej yang berasingan.

Kami sedang menulis pelanggan untuk permintaan kepada API Carian Penerbangan Skyscanner dalam projek

Skyscanner telah memberikan artikel tentang cara menggunakan API mereka (kami tidak akan membuat sesi dengan permintaan aktif). Apakah yang dimaksudkan dengan "menulis pelanggan"? Kami perlu membuat permintaan ke URL tertentu dengan parameter tertentu dan menyediakan DTO (objek pemindahan data) untuk data yang dipindahkan kembali kepada kami. Terdapat empat kumpulan permintaan di tapak:
  1. Carian Penerbangan Langsung - kami tidak akan menganggapnya tidak perlu buat masa ini.
  2. Tempat - mari menulis.
  3. Semak imbas Harga Penerbangan - kami akan menggunakan satu permintaan di mana anda boleh mendapatkan semua maklumat.
  4. Penyetempatan - mari tambahkannya supaya kita tahu data yang disokong.

Buat perkhidmatan pelanggan untuk permintaan Penyetempatan:

Pelannya semudah lobak kukus: buat permintaan, lihat parameter, lihat respons. Terdapat dua pertanyaan: Penanda senarai dan Mata Wang. Mari kita mulakan dengan Mata Wang. Angka tersebut menunjukkan bahawa ini ialah permintaan tanpa medan tambahan: ia diperlukan untuk mendapatkan maklumat tentang mata wang yang disokong: Mencipta sistem pemantauan harga tiket udara: panduan langkah demi langkah [Bahagian 1] - 6Respons adalah dalam bentuk objek JSON, yang mengandungi koleksi objek yang sama, contohnya:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Mari buat CurrencyDto untuk objek ini:
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;
}
di mana:
  • @Data ialah anotasi daripada projek Lombok dan menjana semua kaedah getter, setter, override toString(), equals() dan hashCode(). Perkara yang meningkatkan kebolehbacaan kod dan mempercepatkan masa menulis objek POJO ;
  • @JsonProperty("Kod") ialah anotasi daripada Projek Jackson yang memberitahu medan yang akan diberikan kepada pembolehubah ini. Iaitu, medan dalam JSON bersamaan dengan Kod akan diberikan kepada pembolehubah kod .
Artikel rasmi daripada Skyscanner mencadangkan penggunaan perpustakaan UniRest untuk permintaan REST . Oleh itu, kami akan menulis perkhidmatan lain yang akan melaksanakan permintaan melalui REST. Ini akan menjadi UniRestService . Untuk melakukan ini, tambahkan kebergantungan baharu kepada maven:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Seterusnya, kami akan menulis perkhidmatan yang akan melaksanakan permintaan REST. Sudah tentu, untuk setiap pelanggan/perkhidmatan kami akan mencipta antara muka dan pelaksanaannya:
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);

}
Dan pelaksanaannya:
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;
   }
}
Intipatinya ialah semua permintaan yang kami minati dicipta untuk permintaan GET, dan perkhidmatan ini menerima permintaan siap sedia dan menambah pengepala yang diperlukan seperti:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Untuk mengambil data daripada sifat, gunakan anotasi @Value seperti yang ditunjukkan di bawah:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Ia mengatakan bahawa dalam application.properties akan ada sifat bernama x.rapid.api.key, yang perlu disuntik ke dalam pembolehubah ini. Kami menyingkirkan nilai berkod keras dan memperoleh definisi pembolehubah ini daripada kod program. Lebih-lebih lagi, apabila saya menerbitkan aplikasi ini di GitHub, saya tidak menambah nilai harta ini. Ini dilakukan atas sebab keselamatan. Kami telah menulis perkhidmatan yang akan berfungsi dengan permintaan REST, kini tiba masanya untuk perkhidmatan untuk Penyetempatan. Kami sedang membina aplikasi berdasarkan OOP, jadi kami mencipta antara muka LocalizationClient dan pelaksanaannya 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();

}
dan pelaksanaan 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>>() {
       });
   }
}
di mana
  • @Autowired ialah anotasi yang mengatakan bahawa anda perlu menyuntik objek ke dalam kelas ini dan menggunakannya tanpa menciptanya, iaitu, tanpa operasi Objek baharu;
  • @Component ialah anotasi yang mengatakan bahawa objek ini mesti ditambahkan pada Konteks Aplikasi supaya kemudiannya boleh disuntik menggunakan anotasi @Autowired;
  • ObjectMapper objectMapper ialah objek daripada Projek Jackson yang menterjemah semua ini ke dalam objek Java.
  • CurrencyDTO dan 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;
}
Untuk menyuntik ObjectMapper ke dalam mana-mana bahagian projek, saya menambah mencipta dan menambahkannya pada ApplicationContext melalui kelas konfigurasi.
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;
   }
}
Anotasi @Configuration memberitahu Spring bahawa akan ada beberapa konfigurasi dalam kelas ini. Dan hanya untuk ini saya menambah ObjectMapper. Begitu juga, kami menambah PlacesClient dan 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;
}
dan
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>>() {
       });
   }
}
di mana PlacesDto mempunyai borang:
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;
}
Dan akhirnya, perkhidmatan pelanggan yang, berdasarkan data yang diperlukan, akan mengembalikan harga minimum untuk penerbangan dan semua maklumat yang diperlukan: FlightPriceClient dan FlightPriceClientImpl. Kami akan melaksanakan hanya satu permintaan, 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;
   }
}
di mana FlightClientException kelihatan seperti:
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;
}
Akibatnya, menurut data daripada PlacesCl
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION