如何仅在 Mono 为空时执行操作,如果不为空则抛出错误
How to perform an action only if the Mono is empty and throw an error if not empty
我正在尝试将一个项目转换为使用 Spring WebFlux 并且 运行 遇到一些基本业务逻辑工作的问题。我有一个负责检索/保存记录的存储层和一个负责应用程序业务规则的服务层。我想做的(在服务中)层是检查给定用户名的用户是否已经存在。如果是这样,我想用一个错误来回应。如果没有,我想让插入发生。
我在存储库层调用一个方法,该方法将通过用户名查找用户,如果找不到,它将 return 一个空的 Mono。这是按预期工作的;但是,我尝试了 flatMap 和(defaultIfEmpty 和 swithIfEmpty)的各种组合,但无法编译/构建它。
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(userRepository.insertUser(user));
}
我得到的错误是 Mono<Object> cannot be converted to Mono<User>
,因此 swithIfEmpty
似乎没有反映出适当的类型,而且转换似乎也不起作用。
您收到此编译器错误的原因如下。
flatmap
获取已完成的 Mono
中的内容,并尝试将其转换为它可以推断的任何类型。 Mono.error
包含一个类型,这个类型是 Object
.
一种方法是将您的逻辑移动到平面图中。
// This is just example code using strings instead of repos
public Mono<String> insertUser(String user) {
return Mono.just(user)
// Here we map/convert instead based on logic
.flatMap(__ -> {
if (__.isEmpty())
return Mono.error(new IllegalArgumentException("User already exists with username [" + user + "]"));
return Mono.just(user);
}).switchIfEmpty(Mono.just(user));
}
switchIfEmpty
对于做出合乎逻辑的决定恕我直言并不是特别好。文档说明
Fallback to an alternative Mono if this mono is completed
without data
如果我们没有得到任何东西,它更像是回退到其他东西,所以我们可以保持数据流。
你也可以
Mono.empty().doOnNext(o -> {
throw new IllegalArgumentException("User already exists with username [" + o + "]");
}).switchIfEmpty(Mono.just("hello")).subscribe(System.out::println);
经过额外的测试,并考虑到我的开发人员的反应,我找到了以下解决方案:
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))
.cast(User.class);
}
正如 Thomas 所说,编译器变得很困惑。我的假设是因为 flatMap
返回一个带有错误的 Mono 而 switchIfEmpty
返回一个带有 User 的 Mono 所以它恢复为带有对象的 Mono (因此额外的 .cast
运算符让它编译)。
另一个添加是在 switchMap
中添加 Mono.defer
。否则,switchIfEmpty
总是开火。
我仍然愿意接受其他建议/替代方案(因为这似乎是一个相当普遍的需求/模式)。
我正在使用具有类型参数 E
的抽象 class,因此我无法使用 .cast(E.class)
。我们的解决方案是
private Mono<E> checkIfStatementExists(E statement) {
return this.statementService.getByStatementRequestId(statement.getStatementRequestId())
.flatMap(sr -> Mono.<E>error(new ValidationException("Statement already exists for this request!")))
.switchIfEmpty(Mono.just(statement));
}
我想下周我需要和我的同事讨论这件事。
编辑。我们和同事讨论过,更新后的代码在上面。
遇到了同样的问题,结果如下,
请注意:这不需要类型转换并且适用于两种情况,即
如果元素已存在于数据库中,则抛出错误。
插入元素,否则 return 单声道。
public Mono<UserDTO> insertUser(User user) {
return this.userRepository.findByUsername(user.getUsername())
.flatMap(foundUser-> null != foundUser ? Mono
.error(new UserAlreadyExistsException(ExceptionsConstants.USER_ALREADY_EXISTS_EXCEPTION))
: Mono.just(user))
.switchIfEmpty(this.userRepository.save(user))
.map(userCreated -> copyUtils.createUserDTO(userCreated));
}
我正在尝试将一个项目转换为使用 Spring WebFlux 并且 运行 遇到一些基本业务逻辑工作的问题。我有一个负责检索/保存记录的存储层和一个负责应用程序业务规则的服务层。我想做的(在服务中)层是检查给定用户名的用户是否已经存在。如果是这样,我想用一个错误来回应。如果没有,我想让插入发生。
我在存储库层调用一个方法,该方法将通过用户名查找用户,如果找不到,它将 return 一个空的 Mono。这是按预期工作的;但是,我尝试了 flatMap 和(defaultIfEmpty 和 swithIfEmpty)的各种组合,但无法编译/构建它。
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(userRepository.insertUser(user));
}
我得到的错误是 Mono<Object> cannot be converted to Mono<User>
,因此 swithIfEmpty
似乎没有反映出适当的类型,而且转换似乎也不起作用。
您收到此编译器错误的原因如下。
flatmap
获取已完成的 Mono
中的内容,并尝试将其转换为它可以推断的任何类型。 Mono.error
包含一个类型,这个类型是 Object
.
一种方法是将您的逻辑移动到平面图中。
// This is just example code using strings instead of repos
public Mono<String> insertUser(String user) {
return Mono.just(user)
// Here we map/convert instead based on logic
.flatMap(__ -> {
if (__.isEmpty())
return Mono.error(new IllegalArgumentException("User already exists with username [" + user + "]"));
return Mono.just(user);
}).switchIfEmpty(Mono.just(user));
}
switchIfEmpty
对于做出合乎逻辑的决定恕我直言并不是特别好。文档说明
Fallback to an alternative Mono if this mono is completed without data
如果我们没有得到任何东西,它更像是回退到其他东西,所以我们可以保持数据流。
你也可以
Mono.empty().doOnNext(o -> {
throw new IllegalArgumentException("User already exists with username [" + o + "]");
}).switchIfEmpty(Mono.just("hello")).subscribe(System.out::println);
经过额外的测试,并考虑到我的开发人员的反应,我找到了以下解决方案:
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))
.cast(User.class);
}
正如 Thomas 所说,编译器变得很困惑。我的假设是因为 flatMap
返回一个带有错误的 Mono 而 switchIfEmpty
返回一个带有 User 的 Mono 所以它恢复为带有对象的 Mono (因此额外的 .cast
运算符让它编译)。
另一个添加是在 switchMap
中添加 Mono.defer
。否则,switchIfEmpty
总是开火。
我仍然愿意接受其他建议/替代方案(因为这似乎是一个相当普遍的需求/模式)。
我正在使用具有类型参数 E
的抽象 class,因此我无法使用 .cast(E.class)
。我们的解决方案是
private Mono<E> checkIfStatementExists(E statement) {
return this.statementService.getByStatementRequestId(statement.getStatementRequestId())
.flatMap(sr -> Mono.<E>error(new ValidationException("Statement already exists for this request!")))
.switchIfEmpty(Mono.just(statement));
}
我想下周我需要和我的同事讨论这件事。
编辑。我们和同事讨论过,更新后的代码在上面。
遇到了同样的问题,结果如下,
请注意:这不需要类型转换并且适用于两种情况,即
如果元素已存在于数据库中,则抛出错误。
插入元素,否则 return 单声道。
public Mono<UserDTO> insertUser(User user) { return this.userRepository.findByUsername(user.getUsername()) .flatMap(foundUser-> null != foundUser ? Mono .error(new UserAlreadyExistsException(ExceptionsConstants.USER_ALREADY_EXISTS_EXCEPTION)) : Mono.just(user)) .switchIfEmpty(this.userRepository.save(user)) .map(userCreated -> copyUtils.createUserDTO(userCreated)); }