Создание системы мониторинга цен на авиабилеты: пошаговое руководство [Часть 1]
Создание системы мониторинга цен на авиабилеты: пошаговое руководство [Часть 2]
Содержание
- Пишем уровень Controller’ов. SubscriptionController
- Тестирование приложения
- Планы на развитие
- Выводы
- Полезные ссылки
Пишем уровень 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 — значит, что будет проходить валидация данных, если они не соответствуют, то будет ошибка.
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; }
- @Email — проверяет на правильность написания электронной почты;
- @NotNull — проверяет, что переменная не должна быть пустой.
Тестирование приложения
В статье я не буду описывать тестирование. Тем не менее, тесты на проекте есть, и их можно посмотреть и изучить самостоятельно. Более того, если будут какие-то вопросы, можно задавать их здесь в комментариях: я с удовольствием отвечу на них.Планы на развитие
Проект уже есть и я планирую заниматься им дальше. В ближайшем будущем хочу сделать следующее:- написать отдельно как библиотеку клиент для Skyscanner Flight Search, чтоб можно было использовать это как зависимость не только в этом проекте, но и в других;
- перевести на PostgreSQL, чтоб не терялись данные на Heroku при остановке приложения. Это сделает его более стабильным;
- создать контроллеры для данных клиента, которые поддерживаются им. Например для Places, Currencies, Countries;
- расширить функционал поиска. Там еще есть много опций;
- жду предложения от сообщества.
Выводы
Написать веб-приложение с REST API на основании Spring Boot и экосистемы в целом — это не так сложно, как может показаться. Да, есть нюансы, которые нужно знать. Чтоб прояснить всё, что связано со спрингом, я рекомендую к прочтению Spring in Action 5th edition. После этой книги станет яснее, что здесь происходит. P.S. ее можно найти в вк бесплатно.Полезные ссылки
Все данные, которыми я пользовался при написании проекта и просто полезные ссылки для понимания того, что хорошо бы изучить:- Ссылка на проект: flights-monitoring.
- Ссылка на развернутый проект на хероку.
- Sptring Initializr — быстрый способ сформировать проект с нужными конфигурациями, зависимостями. Ссылка на сформированный проект.
- Skyscanner Flight Search — открытый API для получения данных о полетах.
- Хабр: Введение в Spring Boot: создание простого REST API на Java.
- JavaRush: Введение в Jackson Framework.
- JavaRush: Project Lombok, или объявляем войну бойлерплейту.
- Rapidapi: Skyscanner Flight Search API(Java).
- Wiki: POJO.
- Spring Boot With H2 database.
- Решение проблем с Gmail для отправки писем.
- Spring Boot - how to send email via SMTP.
- Scheduling tasks.
- Setting Up Swagger 2 with a Spring REST API.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ