使用项目反应堆mergeWith()运算符,以实现“ if / elseif / else”分支逻辑

时间:2019-08-26 11:05:53

标签: reactive-programming project-reactor

我正在尝试使用项目反应堆 mergeWith运算符,以实现if/elseif/else分支逻辑,如下所述:RxJS, where is the If-Else Operator

提供的示例是用RxJS编写的,但基本思想保持不变。

基本上,这个想法是在3个filter上使用monos/publishers运算符(因此具有3个不同的谓词)并按如下方式合并3个monos(这里是RxJS {{1} }当然):

Observables

我已经复制并粘贴了以上文章中的相关示例。

请考虑const somethings$ = source$ .filter(isSomething) .do(something); const betterThings$ = source$ .filter(isBetterThings) .do(betterThings); const defaultThings$ = source$ .filter((val) => !isSomething(val) && !isBetterThings(val)) .do(defaultThing); // merge them together const onlyTheRightThings$ = somethings$ .merge( betterThings$, defaultThings$, ) .do(correctThings); something$betterThings$是我们的单声道defaultThings$isSomething是谓词。

现在这是我的3个真实的isBetterThings(用Java编写):

monos/publishers

这是需要合并三个private Mono<ServerResponse> validateUser(User user) { return Mono.just(new BeanPropertyBindingResult(user, User.class.getName())) .doOnNext(err -> userValidator.validate(user, err)) .filter(AbstractBindingResult::hasErrors) .flatMap(err -> status(BAD_REQUEST) .contentType(APPLICATION_JSON) .body(BodyInserters.fromObject(err.getAllErrors())) ); } private Mono<ServerResponse> validateEmailNotExists(User user) { return userRepository.findByEmail(user.getEmail()) .flatMap(existingUser -> status(BAD_REQUEST) .contentType(APPLICATION_JSON) .body(BodyInserters.fromObject("User already exists.")) ); } private Mono<ServerResponse> saveUser(User user) { return userRepository.save(user) .flatMap(newUser -> status(CREATED) .contentType(APPLICATION_JSON) .body(BodyInserters.fromObject(newUser)) ); } 的顶层方法:

publishers

我不确定如何使用public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) { return serverRequest.bodyToMono(User.class) .mergeWith(...) } 运算符...我试过了mergeWith()静态运算符,该操作符需要多个发布者(对我来说是好消息)但返回一个Mono.when()(不好)为我)。

有人可以帮忙吗?

P.S。我相信您会原谅RxJS(js)和Reactor代码(java)之间的混合。我打算利用我在RxJS中的知识来在Reactor应用中实现类似的目标。:-)

编辑1 :我已经尝试过:

Mono<void>

但我收到此错误:public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) { return serverRequest .bodyToMono(User.class) .flatMap(user -> validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user))).single(); }

编辑2 :与(注意括号)相同:

NoSuchElementException: Source was empty

编辑3 :与public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) { return serverRequest .bodyToMono(User.class) .flatMap(user -> validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user)).single()); } 相同的错误:

Mono<User>

编辑4 :我可以确认,三个单声道中的至少一个会一直发出。当我使用public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) { Mono<User> userMono = serverRequest.bodyToMono(User.class); return validateUser(userMono) .or(validateEmailNotExists(userMono)) .or(saveUser(userMono)) .single(); } 运算符时,出现了问题...

如果我使用它,我所有的测试都会通过:

or()

我在这里使用了public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) { return serverRequest.bodyToMono(User.class) .flatMap(user -> Flux.concat(validateUser(user), validateEmailNotExists(user), saveUser(user)).next().single()); } 运算符来保留操作顺序。

您知道concat()运算符出了什么问题吗?

编辑5 :我尝试使用or()运算符,但无济于事:

cache()

1 个答案:

答案 0 :(得分:2)

您当前的代码示例暗示您的3种返回Mono<ServerResponse>的方法应该采用Mono<User>而不是User,因此您可能需要在此处进行一些更改。

但是,我离题了-这似乎不是这里的主要问题。

根据我对该链接中描述的模式的了解,您正在创建3个单独的Mono对象,其中只有一个会返回结果-并且您需要一个Mono原来的3个Mono对象中的3个返回。

在这种情况下,我建议您进行以下操作:

Mono<ServerResult> result = Flux.merge(validateUser(user), validateEmailNotExists(user), saveUser(user)).next().single();

打破现状:

  • 静态Flux.merge()方法使用您的3个Mono对象并将它们合并为Flux;
  • next()Mono的形式返回第一个可用结果;
  • single()将确保Mono发出一个值,该值与所有内容都完全相反,否则将引发异常。 (可选,但只是一点点安全网。)

您也可以像这样链接Mono.or()

Mono<ServerResult> result = validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user)).single();

此方法的优点是:

  • 在某些情况下,它可能更具可读性;
  • 如果您的链中有多个Mono可能会返回一个结果,这将允许您设置选择优先顺序的优先顺序(与上述示例相反,我只会先得到Mono发出的值。)

缺点可能是性能之一。如果saveUser()在上面的代码中首先返回一个值,那么在合并的Mono完成之前,您仍然必须等待其他两个Mono对象完成。