Вы, кажется, нашли ответ, но позвольте мне немного остановиться на нем.
почему вы не можете заблокировать
Полученное сообщение об ошибке указывает на то, что вы пытаетесь вернуться к поведению блокировки внутри определенного 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))
;