Mongo Flux / Mono получить объект / ы - PullRequest
0 голосов
/ 28 июня 2018

Я хочу получить объект / объекты из Flux / Mono. Я использую

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

Я делаю что-то подобное:

    Mono<UserEntity> byEmail = userRepository.findByEmail(userDto.getEmail());
    UserEntity block = byEmail.block();

А у меня ошибка:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3

Почему? Есть ли другой способ получить объект / объекты?

Как в реактивном программировании сделать то, что: В RequestBody у вас есть UserDto.

Убедитесь, что адрес электронной почты существует в базе данных, если не создан пользователь.

ОТВЕТИТЬ НА ОБНОВЛЕНИЕ С @ simon-baslé

 return userRepository.findByEmail(userDto.getEmail())
    //rethrow DB errors as BadRequestException, except user exists
    .onErrorResume(t -> Mono.error(new BadRequestException()))
    //throwing in map is converted to onError signal
    .map(ifItGoesThereItExist-> { throw new UserByEmailExistException(); })
    //switchIfEmpty to replace an empty source with a different Mono
    .switchIfEmpty(createUser(userDto))
    //at this point, map can only receive an onNext from the createUser
    .map(u -> new ResponseEntity(u, HttpStatus.CREATED))
    ;

1 Ответ

0 голосов
/ 28 июня 2018

Вы, кажется, нашли ответ, но позвольте мне немного остановиться на нем.

почему вы не можете заблокировать

Полученное сообщение об ошибке указывает на то, что вы пытаетесь вернуться к поведению блокировки внутри определенного Thread (или пула потоков), который не адаптирован к блокировке. Это поток, используемый Spring Webflux (и под прикрытием Netty) для обработки каждого входящего запроса в приложении . Как следствие, если вы заблокируете его, вы запретите вашему приложению обслуживать новые запросы.

Ваш ответ и несколько небольших улучшений

Во-первых, map можно упростить, поскольку значения null недопустимы в Flux или Mono. Spring Data ReactiveCrudRepository вернет пустой Mono, если значение не в БД, не путать с Mono, который испускает null:

---( null )---|->
onNext(null), onComplete() // onNext(null) being forbidden

против

---|->
onComplete()

Кроме того, я думаю, что с onErrorResume вы намеревались обернуть ошибки БД, кроме случая "пользователь существует"? Если это так, размещение этого onErrorResume неверно, потому что оно похоже на catch(Throwable e), который также поймает UserByEmailExistException. Поместите это перед map. Вы также можете напрямую бросить изнутри карты.

Таким образом, все сводится к обнаружению пустого Mono против значения Mono, замените пустое на асинхронное сохранение в БД, а оцененное - на onError:

TL; DR Дай мне код

return userRepository.findByEmail(userDto.getEmail())
        //rethrow DB errors as BadRequestException, except user exists
        .onErrorResume(t -> Mono.error(new BadRequestException()))
        //throwing in map is converted to onError signal
        .map(ifItGoesThereItExist-> { throw new UserByEmailExistException(); })
        //switchIfEmpty to replace an empty source with a different Mono
        .switchIfEmpty(createUser(userDto))
        //at this point, map can only receive an onNext from the createUser
        .map(u -> new ResponseEntity(u, HttpStatus.CREATED))
        ;
...