我正在尝试使用项目反应堆 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()
答案 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
对象完成。