JavaRush /Java Blog /Random-ID /Membuat sistem pemantauan harga tiket pesawat: panduan la...

Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 1]

Dipublikasikan di grup Random-ID

Isi:

Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 1] - 1Halo semuanya, komunitas JavaRush! Hari ini kita akan berbicara tentang cara menulis aplikasi Spring Boot untuk memantau harga tiket pesawat langkah demi langkah. Artikel ini ditujukan bagi orang-orang yang memiliki gagasan tentang:
  • REST dan bagaimana titik akhir REST dibangun;
  • database relasional;
  • karya pakar (khususnya, apa itu ketergantungan);
  • objek JSON;
  • prinsip pencatatan.
Perilaku yang Diharapkan:
  1. Anda dapat memilih penerbangan untuk tanggal tertentu dan melacak harganya. Pengguna diidentifikasi berdasarkan alamat email. Segera setelah langganan perubahan harga dilakukan, pengguna menerima pemberitahuan melalui email.
  2. Setiap 30 menit (interval ini dikonfigurasi melalui application.properties) harga minimum penerbangan dihitung ulang untuk semua langganan. Jika salah satu nilainya menjadi lebih rendah, pengguna akan menerima pemberitahuan melalui email.
  3. Semua langganan dengan tanggal penerbangan yang sudah ketinggalan zaman akan dihapus.
  4. Melalui REST API Anda dapat:
    • membuat langganan;
    • sunting;
    • menerima semua langganan melalui email;
    • hapus langganan.

Rencana tindakan untuk mencapai tujuan

Anda harus mulai dengan fakta bahwa informasi tentang penerbangan perlu diambil dari suatu tempat. Biasanya, situs web menyediakan REST API terbuka yang dapat digunakan untuk mengambil informasi.

API (antarmuka pemrograman aplikasi) adalah antarmuka yang melaluinya Anda dapat berinteraksi dengan suatu aplikasi. Dari sini kita dapat membangun jembatan menuju apa itu REST API.

REST API adalah antarmuka permintaan REST yang dapat digunakan untuk berkomunikasi dengan aplikasi web.

Untuk melakukan ini, kami akan menggunakan Skyscanner , atau lebih tepatnya, API (di situs web Rakuten API ). Selanjutnya, Anda perlu memilih framework yang tepat sebagai pondasi dasar. Yang paling populer dan diminati adalah ekosistem Spring dan mahkota ciptaannya - Spring Boot. Anda dapat mengunjungi situs resminya, atau membaca artikel di Habré . Untuk menyimpan langganan pengguna kami akan menggunakan database H2 bawaan . Untuk membaca dari JSON ke kelas dan sebaliknya, kita akan menggunakan Proyek Jackson ( ini tautan pada sumber daya kami ). Kami akan menggunakan spring-boot-starter-mail untuk mengirim pesan ke pengguna.Agar aplikasi menghitung ulang harga minimum pada frekuensi tertentu, kami akan menggunakan Spring Scheduler . Untuk membuat REST API kita akan menggunakan spring-boot-starter-web . Agar tidak menulis kode pinjaman (pengambil, penyetel, override sama dengan dan kode hash, toString() untuk objek), kita akan menggunakan Project Lombok . Untuk merasakan dan melihat REST API, kami akan menggunakan Swagger 2 dan langsung Swagger UI (antarmuka pengguna) untuk pelacakan waktu nyata. Begini tampilannya sekarang: Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 1] - 2di mana terdapat 4 kueri lainnya yang berhubungan dengan membuat, mengedit, mendapatkan, dan menghapus langganan.

Menjelajahi API Skyscanner

Mari ikuti tautan ke rakuten api . Pertama, Anda perlu mendaftar. Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 1] - 3Semua ini diperlukan untuk menerima kunci unik untuk menggunakan situs mereka dan membuat permintaan ke API publik yang diposting di dalamnya. Salah satu API tersebut adalah Pencarian Penerbangan Skyscanner yang kita butuhkan . Sekarang mari kita cari tahu cara kerjanya. Mari temukan permintaan GET List Places. Gambar menunjukkan bahwa Anda perlu mengisi data dan memulai Test Endpoint , sebagai hasilnya kami menerima respon dalam bentuk objek JSON di sebelah kanan: Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 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 disubstitusikan ke dalam rumus ini, kita mendapatkan:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
dan dua header akan diteruskan ke 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-keyitu dikeluarkan setelah pendaftaran. Untuk melacak penurunan harga, kita memerlukan titik akhir Telusuri Kutipan . Temukan sendiri :)

Membuat kerangka aplikasi berdasarkan Spring Boot

Untuk membuat proyek dengan cepat dan mudah menggunakan Spring Boot, Anda dapat menggunakan Spring Initializr . Pilih opsi berikut:
  1. Proyek Maven
  2. Jawa
  3. 2.1.10
  4. grup - mana saja yang menurut Anda perlu, misalnya ru.javarush
  5. artefak - persis sama, misalnya pemantauan penerbangan
  6. dalam pencarian ketergantungan kami mencari yang berikut:
    • Jaring Musim Semi
    • Pengirim Surat Java
    • Data Musim Semi Jpa
    • Basis Data H2
Dan kemudian klik Hasilkan . Itu saja: proyek yang sudah selesai akan diunduh sebagai arsip. Jika ada yang tidak berhasil, Anda dapat menggunakan tautan tempat saya menyimpan proyek yang diinginkan . Tentu saja, lebih baik melakukannya sendiri dan memahami cara kerjanya. Aplikasi ini akan terdiri dari tiga lapisan:
  • KONTROLER - masuk ke aplikasi. REST API akan dijelaskan di sini
  • SERVICE adalah lapisan logika bisnis. Seluruh logika aplikasi akan dijelaskan di sini.
  • REPOSITORY - lapisan untuk bekerja dengan database.
Selain itu, kelas yang terkait dengan klien untuk API Pencarian Penerbangan Skyscanner akan menjadi paket terpisah.

Kami sedang menulis klien untuk permintaan ke API Pencarian Penerbangan Skyscanner dalam proyek tersebut

Skyscanner telah dengan baik hati menyediakan artikel tentang cara menggunakan API mereka (kami tidak akan membuat sesi dengan permintaan aktif). Apa artinya "menulis klien"? Kita perlu membuat permintaan ke URL tertentu dengan parameter tertentu dan menyiapkan DTO (objek transfer data) untuk data yang ditransfer kembali kepada kita. Ada empat kelompok permintaan di situs:
  1. Pencarian Penerbangan Langsung - kami tidak akan menganggapnya tidak perlu saat ini.
  2. Tempat - ayo menulis.
  3. Telusuri Harga Penerbangan - kami akan menggunakan satu permintaan di mana Anda bisa mendapatkan semua informasi.
  4. Lokalisasi - mari tambahkan agar kita mengetahui data apa yang didukung.

Buat layanan klien untuk permintaan Pelokalan:

Rencananya sesederhana lobak kukus: buat permintaan, lihat parameternya, lihat responsnya. Ada dua pertanyaan: Daftar penanda dan Mata Uang. Mari kita mulai dengan Mata Uang. Gambar tersebut menunjukkan bahwa ini adalah permintaan tanpa kolom tambahan: diperlukan untuk mendapatkan informasi tentang mata uang yang didukung: Membuat sistem pemantauan harga tiket pesawat: panduan langkah demi langkah [Bagian 1] - 6Responsnya berupa objek JSON yang berisi kumpulan objek yang sama, misalnya:
{
"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 adalah anotasi dari proyek Lombok dan menghasilkan semua metode pengambil, penyetel, penggantian toString(), sama dengan() dan hashCode(). Apa yang meningkatkan keterbacaan kode dan mempercepat waktu penulisan objek POJO ;
  • @JsonProperty("Code") adalah anotasi dari Proyek Jackson yang memberitahukan bidang apa yang akan ditugaskan ke variabel ini. Artinya, bidang di JSON yang sama dengan Kode akan ditetapkan ke variabel kode .
Artikel resmi dari Skyscanner menyarankan penggunaan perpustakaan UniRest untuk permintaan REST . Oleh karena itu, kami akan menulis layanan lain yang akan mengimplementasikan permintaan melalui REST. Ini akan menjadi UniRestService . Untuk melakukan ini, tambahkan ketergantungan baru ke maven:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Selanjutnya, kami akan menulis layanan yang akan melakukan permintaan REST. Tentunya untuk setiap klien/layanan kami akan membuat antarmuka dan implementasinya:
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 implementasinya:
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;
   }
}
Esensinya adalah bahwa semua permintaan yang kami minati dibuat untuk permintaan GET, dan layanan ini menerima permintaan yang sudah jadi dan menambahkan header yang diperlukan seperti:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Untuk mengambil data dari properti, gunakan anotasi @Value seperti yang ditunjukkan di bawah ini:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Dikatakan bahwa di application.properties akan ada properti bernama x.rapid.api.key, yang perlu dimasukkan ke dalam variabel ini. Kami menghilangkan nilai-nilai hardcode dan memperoleh definisi variabel ini dari kode program. Terlebih lagi, ketika saya mempublikasikan aplikasi ini di GitHub saya tidak menambahkan nilai properti ini. Hal ini dilakukan demi alasan keamanan. Kami telah menulis layanan yang akan bekerja dengan permintaan REST, sekarang saatnya layanan untuk Pelokalan. Kami sedang membangun aplikasi berdasarkan OOP, jadi kami membuat antarmuka LocalizationClient dan implementasinya 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 penerapan 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>>() {
       });
   }
}
Di mana
  • @Autowired adalah anotasi yang mengatakan bahwa Anda perlu memasukkan objek ke dalam kelas ini dan menggunakannya tanpa membuatnya, yaitu tanpa operasi Objek baru;
  • @Component adalah anotasi yang mengatakan bahwa objek ini harus ditambahkan ke Konteks Aplikasi agar nantinya dapat disuntikkan menggunakan anotasi @Autowired;
  • ObjectMapper objectMapper adalah objek dari Proyek Jackson yang menerjemahkan semua ini ke dalam objek Java.
  • Mata UangDTO dan NegaraDto:
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 menyuntikkan ObjectMapper ke bagian mana pun dari proyek, saya menambahkan pembuatan dan menambahkannya ke 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 memberi tahu Spring bahwa akan ada beberapa konfigurasi di kelas ini. Dan hanya untuk ini saya menambahkan ObjectMapper. Demikian pula, kami menambahkan 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 memiliki bentuk:
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 terakhir, layanan klien yang, berdasarkan data yang diperlukan, akan mengembalikan harga minimum untuk sebuah penerbangan dan semua informasi yang diperlukan: FlightPriceClient dan FlightPriceClientImpl. Kami hanya akan menerapkan satu permintaan browsingQuotes. Klien Harga Penerbangan:
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 terlihat 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;
}
Hasilnya, menurut data dari PlacesCl
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION