JavaRush /Blog Java /Random-VI /Tạo hệ thống giám sát giá vé máy bay: hướng dẫn từng bước...
Roman Beekeeper
Mức độ

Tạo hệ thống giám sát giá vé máy bay: hướng dẫn từng bước [Phần 1]

Xuất bản trong nhóm

Nội dung:

Tạo hệ thống theo dõi giá vé máy bay: hướng dẫn từng bước [Phần 1] - 1Xin chào mọi người, cộng đồng JavaRush! Hôm nay chúng ta sẽ nói về cách viết ứng dụng Spring Boot để theo dõi giá vé máy bay từng bước. Bài viết dành cho những người có ý tưởng về:
  • REST và cách xây dựng điểm cuối REST;
  • Cơ sở dữ liệu quan hệ;
  • công việc của maven (đặc biệt, sự phụ thuộc là gì);
  • đối tượng JSON;
  • nguyên tắc khai thác gỗ.
Hành vi dự kiến:
  1. Bạn có thể chọn chuyến bay vào một ngày cụ thể và theo dõi giá cho chuyến bay đó. Người dùng được xác định bằng địa chỉ email. Ngay sau khi thực hiện đăng ký thay đổi giá, người dùng sẽ nhận được thông báo qua email.
  2. Cứ sau 30 phút (khoảng thời gian này được định cấu hình thông qua application.properties), giá tối thiểu cho chuyến bay sẽ được tính lại cho tất cả các đăng ký. Nếu một trong các giá trị trở nên thấp hơn, người dùng sẽ nhận được thông báo qua email.
  3. Tất cả các đăng ký có ngày bay lỗi thời sẽ bị xóa.
  4. Thông qua API REST bạn có thể:
    • tạo một thuê bao;
    • biên tập;
    • nhận tất cả các đăng ký qua email;
    • xóa đăng ký.

Kế hoạch hành động để đạt được mục tiêu

Bạn cần bắt đầu với thực tế là thông tin về các chuyến bay cần được lấy từ đâu đó. Thông thường, các trang web cung cấp API REST mở để có thể truy xuất thông tin.

API (giao diện lập trình ứng dụng) là giao diện mà qua đó bạn có thể tương tác với một ứng dụng. Từ đó, chúng ta có thể xây dựng một cầu nối để hiểu REST API là gì.

API REST là giao diện của các yêu cầu REST có thể được sử dụng để giao tiếp với ứng dụng web.

Để làm điều này, chúng tôi sẽ sử dụng Skyscanner , hay đúng hơn là API (trên trang web Rakuten API ). Tiếp theo, bạn cần chọn đúng framework làm nền tảng cơ bản. Phổ biến nhất và có nhu cầu là hệ sinh thái Spring và vương miện do họ tạo ra - Spring Boot. Bạn có thể truy cập trang web chính thức của họ hoặc có thể đọc bài viết trên Habré . Để lưu trữ đăng ký của người dùng, chúng tôi sẽ sử dụng cơ sở dữ liệu H2 tích hợp sẵn . Để đọc từ JSON đến các lớp và ngược lại, chúng tôi sẽ sử dụng Dự án Jackson ( đây là liên kết trên tài nguyên của chúng tôi ). Chúng ta sẽ sử dụng spring-boot-starter-mail để gửi tin nhắn tới người dùng , để ứng dụng tính lại giá tối thiểu theo một tần suất nhất định, chúng ta sẽ sử dụng Spring Scheduler . Để tạo API REST, chúng tôi sẽ sử dụng spring-boot-starter-web . Để không viết mã mượn (getters, setters, ghi đè bằng và mã băm, toString() cho các đối tượng), chúng tôi sẽ sử dụng Project Lombok . Để cảm nhận và xem REST API, chúng ta sẽ sử dụng Swagger 2 và ngay Swagger UI (giao diện người dùng) để theo dõi thời gian thực. Hiện tại nó trông như thế này: Tạo hệ thống giám sát giá vé máy bay: hướng dẫn từng bước [Phần 1] - 2trong đó có 4 truy vấn còn lại tương ứng với việc tạo, chỉnh sửa, nhận và xóa đăng ký.

Khám phá API Skyscanner

Hãy theo liên kết đến rakuten api . Trước tiên, bạn cần phải đăng ký. Tạo hệ thống giám sát giá vé máy bay: hướng dẫn từng bước [Phần 1] - 3Tất cả điều này là cần thiết để nhận được một khóa duy nhất để sử dụng trang web của họ và đưa ra yêu cầu đối với các API công khai được đăng trên đó. Một trong những API này là Tìm kiếm Chuyến bay Skyscanner mà chúng tôi cần . Bây giờ chúng ta hãy tìm hiểu xem nó hoạt động như thế nào. Hãy tìm yêu cầu GET List Places. Hình ảnh cho thấy bạn cần điền dữ liệu và bắt đầu Test Endpoint , kết quả là chúng ta nhận được phản hồi dưới dạng đối tượng JSON ở bên phải: Tạo hệ thống theo dõi giá vé máy bay: hướng dẫn từng bước [Phần 1] - 4và yêu cầu sẽ được tạo như sau:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
và tất cả các tham số sẽ được thay thế vào công thức này, chúng tôi nhận được:

https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
và hai tiêu đề sẽ được chuyển cho các yêu cầu này:

.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
nơi sign-up-for-keynó được phát hành sau khi đăng ký. Để theo dõi việc giảm giá, chúng tôi sẽ cần điểm cuối Duyệt báo giá . Hãy tự tìm nhé :)

Tạo framework ứng dụng dựa trên Spring Boot

Để tạo một dự án với Spring Boot một cách nhanh chóng và dễ dàng, bạn có thể sử dụng Spring Launchizr . Chọn các tùy chọn sau:
  1. Dự án Maven
  2. Java
  3. 2.1.10
  4. nhóm - bất cứ điều gì bạn nghĩ là cần thiết, ví dụ ru.javarush
  5. tạo tác - giống hệt nhau, ví dụ như giám sát chuyến bay
  6. khi tìm kiếm sự phụ thuộc, chúng tôi tìm kiếm những điều sau:
    • Web mùa xuân
    • Người gửi thư Java
    • Dữ liệu mùa xuân Jpa
    • Cơ sở dữ liệu H2
Và sau đó nhấp vào Tạo . Thế là xong: dự án đã hoàn thành sẽ được tải xuống dưới dạng kho lưu trữ. Nếu có điều gì đó không ổn, bạn có thể sử dụng liên kết nơi tôi đã lưu dự án mong muốn . Tất nhiên, tốt hơn là bạn nên tự mình làm việc này và hiểu cách thức hoạt động của nó. Ứng dụng sẽ bao gồm ba lớp:
  • ĐIỀU KHIỂN - đăng nhập vào ứng dụng. API REST sẽ được mô tả ở đây
  • DỊCH VỤ là một lớp logic nghiệp vụ. Toàn bộ logic của ứng dụng sẽ được mô tả ở đây.
  • REPOSITORY - lớp để làm việc với cơ sở dữ liệu.
Ngoài ra, các lớp liên quan đến ứng dụng khách cho API Tìm kiếm Chuyến bay Skyscanner sẽ là một gói riêng biệt.

Chúng tôi đang viết thư cho một khách hàng để gửi yêu cầu tới API Tìm kiếm Chuyến bay Skyscanner trong dự án

Skyscanner đã vui lòng cung cấp một bài viết về cách sử dụng API của họ (chúng tôi sẽ không tạo phiên có yêu cầu hoạt động). "Viết cho khách hàng" nghĩa là gì? Chúng tôi cần tạo yêu cầu tới một URL cụ thể với các tham số nhất định và chuẩn bị DTO (đối tượng truyền dữ liệu) cho dữ liệu được chuyển lại cho chúng tôi. Có bốn nhóm yêu cầu trên trang web:
  1. Tìm kiếm chuyến bay trực tiếp - chúng tôi sẽ không coi nó là không cần thiết vào lúc này.
  2. Địa điểm - hãy viết.
  3. Duyệt giá chuyến bay - chúng tôi sẽ sử dụng một yêu cầu để bạn có thể nhận được tất cả thông tin.
  4. Bản địa hóa - hãy thêm nó để chúng tôi biết dữ liệu nào được hỗ trợ.

Tạo một dịch vụ khách hàng cho yêu cầu Bản địa hóa:

Kế hoạch đơn giản như củ cải hấp: tạo yêu cầu, xem thông số, xem phản hồi. Có hai truy vấn: Danh sách đánh dấu và Tiền tệ. Hãy bắt đầu với Tiền tệ. Hình minh họa cho thấy đây là một yêu cầu không có trường bổ sung: cần lấy thông tin về các loại tiền tệ được hỗ trợ: Tạo hệ thống giám sát giá vé máy bay: hướng dẫn từng bước [Phần 1] - 6Phản hồi ở dạng đối tượng JSON, chứa một tập hợp các đối tượng giống nhau, ví dụ:
{
"Code":"LYD"
"Symbol":"د.ل.‏"
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Hãy tạo một MoneyDto cho đối tượng này:
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;
}
Ở đâu:
  • @Data là một chú thích từ dự án Lombok và tạo ra tất cả các phương thức getters, setters, ghi đè toString(), Equals() và hashCode(). Điều gì cải thiện khả năng đọc mã và tăng tốc thời gian viết đối tượng POJO ;
  • @JsonProperty("Code") là một chú thích từ Dự án Jackson cho biết trường nào sẽ được gán cho biến này. Tức là một trường trong JSON bằng Code sẽ được gán cho biến code .
Bài viết chính thức từ Skyscanner đề xuất sử dụng thư viện UniRest cho các yêu cầu REST . Do đó, chúng tôi sẽ viết một dịch vụ khác sẽ triển khai các yêu cầu thông qua REST. Đây sẽ là UniRestService . Để thực hiện việc này, hãy thêm một phần phụ thuộc mới vào maven:
<dependency>
  <groupId>com.mashape.unirest</groupId>
  <artifactId>unirest-java</artifactId>
  <version>1.4.9</version>
</dependency>
Tiếp theo, chúng ta sẽ viết một dịch vụ thực hiện các yêu cầu REST. Tất nhiên, đối với mỗi khách hàng/dịch vụ, chúng tôi sẽ tạo một giao diện và cách triển khai nó:
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;

/**
* Service, which is manipulating with Rest calls.
*/
public interface UniRestService {

   /**
   * Create GET request based on provided {@param path} with needed headers.
   *
   * @param path provided path with all the needed data
   * @return {@link HttpResponse<jsonnode>} response object.
   */
   HttpResponse<jsonnode> get(String path);

}
Và việc thực hiện nó:
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;
   }
}
Bản chất của nó là tất cả các yêu cầu mà chúng tôi quan tâm đều được tạo cho các yêu cầu GET và dịch vụ này chấp nhận yêu cầu được tạo sẵn và thêm các tiêu đề cần thiết như:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Để lấy dữ liệu từ các thuộc tính, hãy sử dụng chú thích @Value như bên dưới:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Nó nói rằng trong application.properties sẽ có một thuộc tính có tên x.rapid.api.key, cần được đưa vào biến này. Chúng tôi loại bỏ các giá trị được mã hóa cứng và rút ra định nghĩa của biến này từ mã chương trình. Hơn nữa, khi tôi xuất bản ứng dụng này trên GitHub, tôi không thêm giá trị của thuộc tính này. Điều này được thực hiện vì lý do bảo mật. Chúng tôi đã viết một dịch vụ sẽ hoạt động với các yêu cầu REST, giờ là lúc dành cho dịch vụ Bản địa hóa. Chúng tôi đang xây dựng một ứng dụng dựa trên OOP, vì vậy chúng tôi tạo giao diện LocalizationClient và cách triển khai nó 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();

}
và triển khai 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>>() {
       });
   }
}
Ở đâu
  • @Autowired là một chú thích nói rằng bạn cần đưa một đối tượng vào lớp này và sử dụng nó mà không cần tạo nó, tức là không có thao tác Object mới;
  • @Component là chú thích cho biết rằng đối tượng này phải được thêm vào Ngữ cảnh ứng dụng để sau này có thể chèn nó bằng chú thích @Autowired;
  • ObjectMapper objectMapper là một đối tượng từ Dự án Jackson để dịch tất cả những thứ này thành các đối tượng Java.
  • Tiền tệDTO và Quốc giaDto:
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;
}
Để đưa ObjectMapper vào bất kỳ phần nào của dự án, tôi đã thêm việc tạo và thêm nó vào ApplicationContext thông qua một lớp cấu hình.
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;
   }
}
Chú thích @Configuration cho Spring biết rằng sẽ có một số cấu hình trong lớp này. Và chỉ vì điều này mà tôi đã thêm ObjectMapper. Tương tự, chúng ta thêm PlacesClient và 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>>() {
       });
   }
}
trong đó PlacesDto có dạng:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.romankh3.flightsmonitoring.client.service.PlacesClient;
import lombok.Data;

/**
* Using for {@link PlacesClient}.
*/
@Data
public class PlacesDto {

   @JsonProperty("PlaceId")
   private String placeId;

   @JsonProperty("PlaceName")
   private String placeName;

   @JsonProperty("CountryId")
   private String countryId;

   @JsonProperty("RegionId")
   private String regionId;

   @JsonProperty("CityId")
   private String cityId;

   @JsonProperty("CountryName")
   private String countryName;
}
Và cuối cùng, dịch vụ khách hàng, dựa trên dữ liệu cần thiết, sẽ trả về mức giá tối thiểu cho chuyến bay và tất cả thông tin cần thiết: FlightPriceClient và FlightPriceClientImpl. Chúng tôi sẽ chỉ thực hiện một yêu cầu, duyệtQuotes. Chuyến bayPriceKhách hàng:
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);
}
Chuyến bayGiáKhách hàngImpl
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;
   }
}
nơi FlightClientException trông giống như:
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;
}
Kết quả là, theo dữ liệu từ PlacesCl
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION