03: WebFlux Web CRUD Практика
предисловие
В предыдущей статье создается простая служба на основе функциональных конечных точек, реализующая Hello . В этой статье используется технология уровня управления аннотациями Spring Boot WebFlux для создания приложения CRUD WebFlux, чтобы сделать разработку более удобной. Здесь мы не обращаемся к хранилищу базы данных, потому что поговорим об этом позже, а здесь в основном говорим о полноценном WebFlux CRUD.
структура
Этот проект будет управлять городом и осуществлять операции CRUD. После того, как проект создан и написан, получается следующая структура, и его структура каталогов выглядит следующим образом:
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── org
│ │ └── spring
│ │ └── springboot
│ │ ├── Application.java
│ │ ├── dao
│ │ │ └── CityRepository.java
│ │ ├── domain
│ │ │ └── City.java
│ │ ├── handler
│ │ │ └── CityHandler.java
│ │ └── webflux
│ │ └── controller
│ │ └── CityWebFluxController.java
│ └── resources
│ └── application.properties
└── target
Как и в случае со структурой каталогов, нам нужно написать следующее по порядку:
- объект
- Репозиторий классов уровня доступа к данным
- Класс обработчика Обработчик
- Класс контроллера Контроллер
объект
Создайте новый пакет org.spring.springboot.domain в качестве класса объектов для записи объектов города. Создайте новый объект City City, код выглядит следующим образом:
/**
* 城市实体类
*
*/
public class City {
/**
* 城市编号
*/
private Long id;
/**
* 省份编号
*/
private Long provinceId;
/**
* 城市名称
*/
private String cityName;
/**
* 描述
*/
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getProvinceId() {
return provinceId;
}
public void setProvinceId(Long provinceId) {
this.provinceId = provinceId;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Город содержит номер города, номер провинции, название города и описание. В конкретной разработке инструменты Lombok будут использоваться для устранения многословного кода Java, особенно методов получения/установки POJO. Подробную информацию можно найти на официальном сайте Ломбока по адресу: projectlombok.org.
Уровень доступа к данным CityRepository
Создайте новый пакет org.spring.springboot.dao в качестве репозитория для написания класса слоя доступа к данным города. Создайте новый CityRepository со следующим кодом:
import org.spring.springboot.domain.City;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
@Repository
public class CityRepository {
private ConcurrentMap<Long, City> repository = new ConcurrentHashMap<>();
private static final AtomicLong idGenerator = new AtomicLong(0);
public Long save(City city) {
Long id = idGenerator.incrementAndGet();
city.setId(id);
repository.put(id, city);
return id;
}
public Collection<City> findAll() {
return repository.values();
}
public City findCityById(Long id) {
return repository.get(id);
}
public Long updateCity(City city) {
repository.put(city.getId(), city);
return city.getId();
}
public Long deleteCity(Long id) {
repository.remove(id);
return id;
}
}
@RepositoryИспользуется для маркировки компонентов доступа к данным, то есть компонентов DAO. Код реализации использует имяrepositoryОбъект Map хранится как данные памяти, и для объекта реализуется определенная бизнес-логика.CityRepository Отвечает за упаковку и организацию уровня сохраняемости книги (операции с данными) для выполнения таких операций, как добавление, запрос и удаление.
Хранилище данных здесь не задействовано, а конкретное хранилище данных будет представлено позже.
Класс обработчика Обработчик
Создайте новый пакет org.spring.springboot.handler в качестве класса обработчика города CityHandler. Создайте новый CityHandler со следующим кодом:
import org.spring.springboot.dao.CityRepository;
import org.spring.springboot.domain.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
public class CityHandler {
private final CityRepository cityRepository;
@Autowired
public CityHandler(CityRepository cityRepository) {
this.cityRepository = cityRepository;
}
public Mono<Long> save(City city) {
return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.save(city)));
}
public Mono<City> findCityById(Long id) {
return Mono.justOrEmpty(cityRepository.findCityById(id));
}
public Flux<City> findAllCity() {
return Flux.fromIterable(cityRepository.findAll());
}
public Mono<Long> modifyCity(City city) {
return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.updateCity(city)));
}
public Mono<Long> deleteCity(Long id) {
return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.deleteCity(id)));
}
}
@ComponentОтносится к компонентам в целом. Если компоненты не классифицированы должным образом, используйте эту аннотацию для аннотации. затем используйтеfinalа также@AutowiredАннотация заключается в том, чтобы внедрить CityRepository Bean в конструктор, и код выглядит следующим образом:
private final CityRepository cityRepository;
@Autowired
public CityHandler(CityRepository cityRepository) {
this.cityRepository = cityRepository;
}
Как видно из возвращаемого значения, Mono и Flux подходят для двух сценариев, а именно:
- Mono: реализует издателя и возвращает 0 или 1 элемент, т.е. один объект
- Flux: реализует издателя и возвращает N элементов, которые являются объектом списка List.
Можно спросить, почему это не возвращает объекты напрямую, такие как City/Long/List. Причина в том, что использование Flux и Mono напрямую — это неблокирующий метод записи, который эквивалентен методу обратного вызова. Использование функционального стиля уменьшает количество обратных вызовов, поэтому соответствующий интерфейс не виден. Именно в этом преимущество WebFlux: неблокирующий + асинхронный вместе взятые.
Mono
Что такое Моно? Официальное описание выглядит следующим образом: Reactive Streams Publisher с базовыми операторами rx, который успешно завершается отправкой элемента или с ошибкой.
Mono — это реактивный потоковый издатель с базовым оператором rx. Элементы или ошибки могут быть успешно опубликованы. как показано на рисунке:
Обычно используемые моно методы:
- Mono.create(): используйте MonoSink для создания Mono
- Mono.justOrEmpty(): создает Mono из необязательного объекта или нулевого объекта.
- Mono.error(): создает Mono, содержащий только сообщение об ошибке.
- Mono.never(): создает Mono, который не содержит уведомлений о сообщениях.
- Mono.delay(): после указанного времени задержки создайте Mono, получая число 0 в качестве уникального значения.
Flux
Что такое Флюс? Официальное описание выглядит следующим образом: Reactive Streams Publisher с операторами rx, который выдает от 0 до N элементов, а затем завершает работу (успешно или с ошибкой).
Flux — это реактивный потоковый издатель с базовым оператором rx. Может успешно публиковать от 0 до N элементов или ошибок. Flux на самом деле является дополнением к Mono. как показано на рисунке:
Так что будьте осторожны: если вы знаете, что издатель равен 0 или 1, используйте Mono.
Самое примечательное в Flux — это метод fromIterable. fromIterable(Iterable it) может публиковать элементы типа Iterable. Конечно, Flux также включает в себя базовые операции: map, merge, concat, flatMap, take, которые здесь не будут представлены.
Класс контроллера Контроллер
При разработке Spring Boot WebFlux настройка не требуется. Spring Boot WebFlux может быть разработан с использованием модели, управляемой аннотациями, с автоматической настройкой.
Новый каталог пакетовorg.spring.springboot.webflux.controllerи создайте каталог с именем CityWebFluxController для обработки различных бизнес-запросов HTTP Restful. код показывает, как показано ниже:
import org.spring.springboot.domain.City;
import org.spring.springboot.handler.CityHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping(value = "/city")
public class CityWebFluxController {
@Autowired
private CityHandler cityHandler;
@GetMapping(value = "/{id}")
public Mono<City> findCityById(@PathVariable("id") Long id) {
return cityHandler.findCityById(id);
}
@GetMapping()
public Flux<City> findAllCity() {
return cityHandler.findAllCity();
}
@PostMapping()
public Mono<Long> saveCity(@RequestBody City city) {
return cityHandler.save(city);
}
@PutMapping()
public Mono<Long> modifyCity(@RequestBody City city) {
return cityHandler.modifyCity(city);
}
@DeleteMapping(value = "/{id}")
public Mono<Long> deleteCity(@PathVariable("id") Long id) {
return cityHandler.deleteCity(id);
}
}
Здесь интерфейс реализован в стиле REST. Так что же такое REST?
REST — это архитектурный стиль, принадлежащий самому WEB и реализованный в соответствии со спецификацией HTTP 1.1. Полное название Representational State Transfer переводится как преобразование представительного состояния. Ресурс: Ресурс. Например, лента новостей; Репрезентативность: представление, такое как JSON, форматированный текст и т. д.; Передача состояния: изменение состояния. Реализовано через действия HTTP.
Чтобы понять REST, нужно понять пять ключевых элементов:
- Ресурс
- Представление ресурсов
- Государственная передача
- Единый интерфейс
- Гипертекстовый привод
6 основных особенностей:
- Ресурсно-ориентированный
- Адресуемость
- Связность
- Безгражданство
- Единый интерфейс
- Гипертекстовый привод
Детали здесь не раскрываются, см. http://www.infoq.com/cn/articles/understanding-restful-style.
Знание ввода запроса, фильтров, перенаправления, преобразования и форматирования будет таким же, как и предыдущее знание MVC.Подробности см. в документе: https://docs.spring.io/spring/docs/current/spring-framework -reference/web-reactive.html
Запустить проект
Разработан проект CRUD Spring Boot Webflux, запустим проект для проверки. Используйте панель инструментов в правой части IDEA, нажмите вкладку «Проект Maven», нажмите «Использовать подключаемый модуль Maven».installЗаказ. Или используйте форму командной строки, в корневом каталоге проекта выполните Maven, чтобы очистить и установить команду проекта:
cd springboot-webflux-2-restful
mvn clean install
Смотрите успешный вывод в консоли:
... 省略
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:30 min
[INFO] Finished at: 2017-10-15T10:00:54+08:00
[INFO] Final Memory: 31M/174M
[INFO] ------------------------------------------------------------------------
Выполнить в IDEAApplicationЗапуск класса в обычном режиме или в режиме отладки. Результат успешного запуска можно увидеть в консоли:
... 省略
2018-04-10 08:43:39.932 INFO 2052 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-04-10 08:43:39.935 INFO 2052 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2018-04-10 08:43:39.960 INFO 2052 --- [ main] org.spring.springboot.Application : Started Application in 6.547 seconds (JVM running for 9.851)
Откройте инструмент POST MAN, необходимый для разработки. Сделайте следующее:
Добавить информацию о городе POST http://127.0.0.1:8080/city
Получить список информации о городе GET http://127.0.0.1:8080/city
Другие интерфейсы демонстрироваться не будут.
Суммировать
Здесь рассматриваются некоторые функции Spring WebFlux для создания базовых проектов CRUD без базовой базы данных. Чтобы лучше показать, как создать поток Flux и как с ним работать. Далее будет описано, как работать с хранилищем данных.
Эта статья опубликована в блогеOpenWriteвыпускать!