反应性嵌套 flatMap 调用的问题

Issue with reactive nested flatMap calls

我需要对两个 Monos 执行操作。 困难在于一个取决于另一个的结果。

让我解释一下:

这是我在 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)))
                         );
}