反应性嵌套 flatMap 调用的问题
Issue with reactive nested flatMap calls
我需要对两个 Monos
执行操作。 困难在于一个取决于另一个的结果。
让我解释一下:
我有一个 Mono<User>
(我从 ServerRequest
得到它;User
是一个 POJO)。
我需要能够从上面的 Mono
中提取用户电子邮件并将其传递给 UserRepository
以检查该电子邮件是否已存在于数据库中。
如果用户已经存在我会抛出一个400
错误;否则,我将保存包含在 ServerRequest
.
中的用户
这是我在 handler
中尝试过的:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest) {
return serverRequest.bodyToMono(User.class)
.flatMap(user -> userRepository
.findByEmail(user.getEmail())
.flatMap(foundUser -> {
if (foundUser != null) {
System.out.println("found:" + foundUser);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Email already exists");
} else {
System.out.println("creating" + user);
return status(CREATED).contentType(APPLICATION_JSON).body(userRepository.save(user), User.class);
}
}));
}
User
:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
private Integer id;
@Size(min = 2)
private String firstName;
@Size(min = 2)
private String lastName;
@Email
private String email;
}
UserRepository
:
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
@Query("select id, first_name, last_name, email from user u where u.email = :email")
Mono<User> findByEmail(String email);
}
但是,我的订阅似乎有问题:调用端点时调用了我的 System.out.println
中的 none。有人可以帮忙吗?
edit 1:这里是router
调用上面的handler
方法:
@Configuration
public class UserRouter {
@Bean
public RouterFunction<ServerResponse> route(UserHandler userHandler) {
return RouterFunctions.route()
.GET("/api/user", accept(APPLICATION_JSON), userHandler::getUsers)
.POST("/api/sign-up", accept(APPLICATION_JSON), userHandler::saveUser)
.build();
}
}
这里的问题是,当找不到用户时,您希望得到一个 null,但是,在反应流中,null 是无效的。相反,反应流有专门的空状态和专门的运算符来处理空情况。
在您的示例中,您可以执行以下操作:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest)
{
return serverRequest.bodyToMono(User.class)
.flatMap(this::createUserIfNotExists);
}
private Mono<ServerResponse> createUserIfNotExists(User user)
{
return userRepository.findByEmail(user.getEmail())
.hasElement()
.flatMap(foundUser ->
{
if (foundUser)
{
System.out.println("found user");
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Email already exists");
} else
{
System.out.println("creating user");
return status(CREATED).contentType(APPLICATION_JSON)
.body(userRepository.save(user), User.class);
}
});
}
或其他选择:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest)
{
return serverRequest.bodyToMono(User.class)
.flatMap(this::createUserIfNotExists);
}
private Mono<ServerResponse> createUserIfNotExists(User user)
{
return userRepository.findByEmail(user.getEmail())
.flatMap(foundUser ->
status(BAD_REQUEST)
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject("User already exists."))
)
.switchIfEmpty(
userRepository.save(user)
.flatMap(newUser -> status(CREATED).contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject(newUser)))
);
}
我需要对两个 Monos
执行操作。 困难在于一个取决于另一个的结果。
让我解释一下:
我有一个
Mono<User>
(我从ServerRequest
得到它;User
是一个 POJO)。我需要能够从上面的
Mono
中提取用户电子邮件并将其传递给UserRepository
以检查该电子邮件是否已存在于数据库中。如果用户已经存在我会抛出一个
400
错误;否则,我将保存包含在ServerRequest
. 中的用户
这是我在 handler
中尝试过的:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest) {
return serverRequest.bodyToMono(User.class)
.flatMap(user -> userRepository
.findByEmail(user.getEmail())
.flatMap(foundUser -> {
if (foundUser != null) {
System.out.println("found:" + foundUser);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Email already exists");
} else {
System.out.println("creating" + user);
return status(CREATED).contentType(APPLICATION_JSON).body(userRepository.save(user), User.class);
}
}));
}
User
:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
private Integer id;
@Size(min = 2)
private String firstName;
@Size(min = 2)
private String lastName;
@Email
private String email;
}
UserRepository
:
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
@Query("select id, first_name, last_name, email from user u where u.email = :email")
Mono<User> findByEmail(String email);
}
但是,我的订阅似乎有问题:调用端点时调用了我的 System.out.println
中的 none。有人可以帮忙吗?
edit 1:这里是router
调用上面的handler
方法:
@Configuration
public class UserRouter {
@Bean
public RouterFunction<ServerResponse> route(UserHandler userHandler) {
return RouterFunctions.route()
.GET("/api/user", accept(APPLICATION_JSON), userHandler::getUsers)
.POST("/api/sign-up", accept(APPLICATION_JSON), userHandler::saveUser)
.build();
}
}
这里的问题是,当找不到用户时,您希望得到一个 null,但是,在反应流中,null 是无效的。相反,反应流有专门的空状态和专门的运算符来处理空情况。
在您的示例中,您可以执行以下操作:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest)
{
return serverRequest.bodyToMono(User.class)
.flatMap(this::createUserIfNotExists);
}
private Mono<ServerResponse> createUserIfNotExists(User user)
{
return userRepository.findByEmail(user.getEmail())
.hasElement()
.flatMap(foundUser ->
{
if (foundUser)
{
System.out.println("found user");
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Email already exists");
} else
{
System.out.println("creating user");
return status(CREATED).contentType(APPLICATION_JSON)
.body(userRepository.save(user), User.class);
}
});
}
或其他选择:
public Mono<ServerResponse> saveUser(ServerRequest serverRequest)
{
return serverRequest.bodyToMono(User.class)
.flatMap(this::createUserIfNotExists);
}
private Mono<ServerResponse> createUserIfNotExists(User user)
{
return userRepository.findByEmail(user.getEmail())
.flatMap(foundUser ->
status(BAD_REQUEST)
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject("User already exists."))
)
.switchIfEmpty(
userRepository.save(user)
.flatMap(newUser -> status(CREATED).contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject(newUser)))
);
}