我有两个办法。
主要方法:
@PostMapping("/login")
public Mono<ResponseEntity<ApiResponseLogin>> loginUser(@RequestBody final LoginUser loginUser) {
return socialService.verifyAccount(loginUser)
.flatMap(socialAccountIsValid -> {
if (socialAccountIsValid) {
return this.userService.getUserByEmail(loginUser.getEmail())
.switchIfEmpty(insertUser(loginUser))
.flatMap(foundUser -> updateUser(loginUser, foundUser))
.map(savedUser -> {
String jwts = jwt.createJwts(savedUser.get_id(), savedUser.getFirstName(), "user");
return new ResponseEntity<>(HttpStatus.OK);
});
} else {
return Mono.just(new ResponseEntity<>(HttpStatus.UNAUTHORIZED));
}
});
}
而这个被调用的方法(服务调用外部API):
public Mono<User> getUserByEmail(String email) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(USER_API_BASE_URI)
.queryParam("email", email);
return this.webClient.get()
.uri(builder.toUriString())
.exchange()
.flatMap(resp -> {
if (Integer.valueOf(404).equals(resp.statusCode().value())) {
return Mono.empty();
} else {
return resp.bodyToMono(User.class);
}
});
}
在上面的示例中,switchIfEmpty()
始终从main方法调用,即使返回的结果为Mono.empty()
。
我找不到解决这个简单问题的办法。
以下也不起作用:
Mono.just(null)
因为方法会掷回NullPointerException
。
我也不能使用flatMap方法来检查foundUser
是否为空。
遗憾的是,如果我返回Mono.empty()
,flatMap根本不会被调用,所以我也不能在这里添加条件。
@SimY4
@PostMapping("/login")
public Mono<ResponseEntity<ApiResponseLogin>> loginUser(@RequestBody final LoginUser loginUser) {
userExists = false;
return socialService.verifyAccount(loginUser)
.flatMap(socialAccountIsValid -> {
if (socialAccountIsValid) {
return this.userService.getUserByEmail(loginUser.getEmail())
.flatMap(foundUser -> {
return updateUser(loginUser, foundUser);
})
.switchIfEmpty(Mono.defer(() -> insertUser(loginUser)))
.map(savedUser -> {
String jwts = jwt.createJwts(savedUser.get_id(), savedUser.getFirstName(), "user");
return new ResponseEntity<>(HttpStatus.OK);
});
} else {
return Mono.just(new ResponseEntity<>(HttpStatus.UNAUTHORIZED));
}
});
}
2条答案
按热度按时间rekjcdws1#
这是因为switchIfEmpty“按值”接受Mono,这意味着即使在你订阅Mono之前,这个替代Mono的评估已经被触发。
设想这样一种方法:
如果您像这样定义代码:
在流构建过程中,无论发生什么情况,它总是会触发替代。
这样,当请求替代时,它将仅打印“Hi there”
统一产品数据:
详细说明一下我的答案。您所面临的问题与Reactor无关,而是与Java语言本身以及它如何解析方法参数有关。让我们检查一下我提供的第一个示例中的代码。
我们可以将其改写为:
这两个代码片段在语义上是等价的。我们可以继续展开它们,看看问题出在哪里:
正如你所看到的,当我们开始组合
Mono
类型时,未来的计算已经被触发了。为了防止不必要的计算,我们可以将未来的计算 Package 到一个延迟的求值中:它将展开成
在第二个例子中,future被困在一个懒惰的供应商中,只有当它被请求时才被调度执行。
统一产品代码:2022:
自从一段时间以来,project reactor提供了一个替代的API来 Package 急切计算的future,这导致了同样的结果-在一个懒惰的供应商中捕获急切计算:
46scxncf2#
对于那些,尽管投票结果很好的答案,仍然不明白为什么这样的行为:
React堆来源(Mono.xxx和Flux.xxx)为:
*延迟评估:- 仅当订户订阅源内容时才评估/触发源内容;
像
Mono.just(xxx)
、Flux.just(xxx)
、Flux.fromIterable(x,y,z)
这样的表达式是急切的。通过使用
defer()
,可以强制对源代码进行延迟求值,这就是为什么接受的答案有效的原因。所以这样做:
buildError()
依赖于急切的源来创建替代Mono将始终在订阅之前进行评估:要防止出现这种情况,请执行以下操作:
阅读此answer了解更多信息。