JavaRush /Java блог /Random UA /Створення системи моніторингу цін на авіаквитки: покроков...
Roman Beekeeper
35 рівень

Створення системи моніторингу цін на авіаквитки: покрокове керівництво [Частина 3]

Стаття з групи Random UA
Створення системи моніторингу цін на авіаквитки: покрокове керівництво [Частина 1] Створення системи моніторингу цін на авіаквитки: покрокове керівництво [Частина 2]

Зміст

Створення системи моніторингу цін на авіаквитки: покрокове керівництво [Частина 3] - 1

Пишемо рівень Controller'ів. SubscriptionController

Останній етап - написання REST API, через який спілкуватимемося з додатком. Для цього буде використовуватися Spring boot starter web . У SubscriptionController буде 4 методи для CRUD операцій. Для контролерів є набір анотацій, за допомогою яких це працює:
  • @Controller — використовується для додавання до ApplicationContext;
  • @RequestMapping("path") - визначає, що в цьому класі будуть REST методи, також path - шлях, на якому буде починатися запит;
  • @PostMapping — для запитів POST, використовується для створення;
  • @ GetMapping - для GET запитів, використовується для читання;
  • @PutMapping – для PUT запитів, використовується для редагування;
  • @DeleteMapping — для DELETE запитів, що використовується для видалення;
  • @PathVariable - значить змінна буде задана в URI запиту;
  • @RequestBody означає, що дані будуть лежати в тілі запиту;
  • @Valid - означає, що проходитиме валідація даних, якщо вони не відповідають, то буде помилка.
SubscriptionController
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionCreateDto;
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionDto;
import com.github.romankh3.flightsmonitoring.rest.dto.SubscriptionUpdateDto;
import com.github.romankh3.flightsmonitoring.service.SubscriptionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* {@link Controller} to handle Subscriptions.
*/
@Api(value = "Operations with Subscriptions", tags = "Subscription Controller")
@RequestMapping(SubscriptionController.SUBSCRIPTION_CONTROLLER_EP)
@Controller
public class SubscriptionController {

   public static final String SUBSCRIPTION_CONTROLLER_EP = "/subscription";

   @Autowired
   private SubscriptionService subscriptionService;

   @ApiOperation("Create new subscription based on SubscriptionDto")
   @PostMapping
   public @ResponseBody
   SubscriptionDto create(@RequestBody @Valid SubscriptionCreateDto dto) {
       return subscriptionService.create(dto);
   }

   @ApiOperation("Finds all subscriptions based on email")
   @GetMapping("/{email}")
   public @ResponseBody
   List<SubscriptionDto> findByEmail(@PathVariable final String email) {
       return subscriptionService.findByEmail(email);
   }

   @ApiOperation("Updates subscription based on it ID")
   @PutMapping("/{id}")
   public SubscriptionDto update(@PathVariable final Long id,
           @RequestBody @Valid SubscriptionUpdateDto dto) {
       return subscriptionService.update(id, dto);
   }

   @ApiOperation("Deletes subscription based on it ID")
   @DeleteMapping("/{id}")
   public void delete(@PathVariable final Long id) {
       subscriptionService.delete(id);
   }
}
Також визначимо які нові класи DTO додалися:
  • SubscriptionCreateDto

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.github.romankh3.flightsmonitoring.repository.entity.Subscription;
    import io.swagger.annotations.ApiModelProperty;
    import java.time.LocalDate;
    import javax.validation.constraints.Email;
    import javax.validation.constraints.NotNull;
    import lombok.Data;
    
    /**
    * Data transfer object to create a {@link Subscription} object.
    */
    @Data
    public class SubscriptionCreateDto {
    
       @NotNull
       @Email
       @ApiModelProperty(value = "Subscriber's email", example = "test@test.com")
       private String email;
    
       @NotNull
       @ApiModelProperty(value = "Country Code", example = "UA")
       private String country;
    
       @NotNull
       @ApiModelProperty(value = "Currency Code", example = "UAH")
       private String currency;
    
       @NotNull
       @ApiModelProperty(value = "Locale", example = "ru-RU")
       private String locale;
    
       @NotNull
       @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky")
       private String originPlace;
    
       @NotNull
       @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky")
       private String destinationPlace;
    
       @NotNull
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date front", example = "2019-12-18")
       private LocalDate outboundPartialDate;
    
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date back", example = "2019-12-25")
       private LocalDate inboundPartialDate;
    }
  • SubscriptionUpdateDto

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.github.romankh3.flightsmonitoring.repository.entity.Subscription;
    import io.swagger.annotations.ApiModelProperty;
    import java.time.LocalDate;
    import javax.validation.constraints.Email;
    import javax.validation.constraints.NotNull;
    import lombok.Data;
    
    /**
    * Dto for updating {@link Subscription} object.
    */
    @Data
    public class SubscriptionUpdateDto {
    
       @NotNull
       @Email
       @ApiModelProperty(value = "Subscriber's email", example = "test@test.com")
       private String email;
    
       @NotNull
       @ApiModelProperty(value = "Country Code", example = "UA")
       private String country;
    
       @NotNull
       @ApiModelProperty(value = "Currency Code", example = "UAH")
       private String currency;
    
       @NotNull
       @ApiModelProperty(value = "Locale", example = "ru-RU")
       private String locale;
    
       @NotNull
       @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky")
       private String originPlace;
    
       @NotNull
       @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky")
       private String destinationPlace;
    
       @NotNull
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date front", example = "2019-12-18")
       private LocalDate outboundPartialDate;
    
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date back", example = "2019-12-25")
       private LocalDate inboundPartialDate;
    }
  • SubscriptionDto

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto;
    import io.swagger.annotations.ApiModelProperty;
    import java.time.LocalDate;
    import javax.validation.constraints.Email;
    import javax.validation.constraints.NotNull;
    import lombok.Data;
    
    /**
    * Data transfer object to see all the data related to subscription.
    */
    @Data
    public class SubscriptionDto {
    
       private Long id;
    
       @NotNull
       @Email
       @ApiModelProperty(value = "Subscriber's email", example = "test@test.com")
       private String email;
    
       @NotNull
       @ApiModelProperty(value = "Country Code", example = "UA")
       private String country;
    
       @NotNull
       @ApiModelProperty(value = "Currency Code", example = "UAH")
       private String currency;
    
       @NotNull
       @ApiModelProperty(value = "Locale", example = "ru-RU")
       private String locale;
    
       @NotNull
       @ApiModelProperty(value = "Code of the origin place", example = "HRK-sky")
       private String originPlace;
    
       @NotNull
       @ApiModelProperty(value = "Code of the destination place", example = "KBP-sky")
       private String destinationPlace;
    
       @NotNull
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date front", example = "2019-12-18")
       private LocalDate outboundPartialDate;
    
       @JsonFormat(pattern = "yyyy-MM-dd")
       @ApiModelProperty(value = "Date back", example = "2019-12-25")
       private LocalDate inboundPartialDate;
    
       @ApiModelProperty(value = "Min price based on all these data", example = "100")
       private Integer minPrice;
    
       @ApiModelProperty(value = "Response which contains all the need info about min price flight")
       private FlightPricesDto flightPricesDto;
    }
У DTO є анотації з Bean Validation API ( стаття на хабрі ), такі як:
  • @ Email – перевіряє на правильність написання електронної пошти;
  • @NotNull - Перевіряє, що змінна не повинна бути порожньою.
І це все ... Повністю проект можна подивитися на GitHub flights-monitoring . Більше того, він зараз розгорнутий на Heroku і його можна подивитися тут . PS не дивуйтеся, що довго вантажиться перший запит. Це обліковий запис безкоштовний, і тому після 30 хвабон бездіяльності хероку зупиняє програму і при запиті він його назад розгортає. Тому дані не зберігаються, оскільки при зупинці H2 вбиває всі дані.

Тестування програми

У статті я не описуватиму тестування. Тим не менш, тести на проекті є , і їх можна подивитися та вивчити самостійно. Більше того, якщо будуть якісь питання, можна ставити їх тут у коментарях: я із задоволенням відповім на них.

Плани на розвиток

Проект уже є, і я планую займатися ним далі. У найближчому майбутньому хочу зробити таке:
  • написати окремо як бібліотеку клієнт для Skyscanner Flight Search, щоб можна було використовувати це як залежність у цьому проекті, а й у інших;
  • перевести на PostgreSQL, щоб не губабося дані на Heroku при зупинці програми. Це зробить його стабільнішим;
  • створити контролери даних клієнта, які підтримуються ним. Наприклад для Places, Currencies, Countries;
  • розширити функціонал пошуку. Там є ще багато опцій;
  • чекаю пропозиції від спільноти.

Висновки

Написати веб-додаток з REST API на основі Spring Boot та екосистеми загалом – це не так складно, як може здатися. Так, є нюанси, які треба знати. Щоб прояснити все, що пов'язане зі спрингом, я рекомендую прочитати Spring in Action 5th edition . Після цієї книги стане ясніше, що тут відбувається. PS її можна знайти у вк безкоштовно.

Корисні посилання

Всі дані, якими я користувався при написанні проекту та просто корисні посилання для розуміння того, що добре б вивчити:
  1. Посилання на проект: flights-monitoring .
  2. Посилання на розгорнутий проект на хероку .
  3. Sptring Initializr – швидкий спосіб сформувати проект із потрібними конфігураціями, залежностями. Посилання на сформований проект .
  4. Skyscanner Flight Search — відкритий API для отримання даних про польоти.
  5. Хабр: Введення у Spring Boot: створення простого REST API на Java .
  6. JavaRush: Вступ до Jackson Framework .
  7. JavaRush: Project Lombok, або оголошуємо війну бойлерплейту .
  8. Rapidapi: Skyscanner Flight Search API(Java) .
  9. Wiki: POJO .
  10. Spring Boot With H2 database .
  11. Вирішення проблем з Gmail для надсилання листів.
  12. Spring Boot - how to send email via SMTP.
  13. Scheduling tasks.
  14. Setting Up Swagger 2 with a Spring REST API.
Дивіться також інші мої статті:
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ