【问题标题】:Spring WebFlux - how to get data from request?Spring WebFlux - 如何从请求中获取数据?
【发布时间】:2019-02-06 13:17:25
【问题描述】:

尝试将我的 Spring Boot 应用程序迁移到 WebFlux,我开始转换 api 层,同时保持存储库不变(即数据库访问是同步和阻塞的)。我遇到了如何从 Mono/Flux 类型获取数据并将它们转发到存储库的问题。

考虑以下

@POST
@Path("/register")
public String register( String body ) throws Exception
{
    ObjectMapper objectMapper = json();

    User user = objectMapper.readValue( body, User.class );

    int random = getRandomNumber( 111111, 999999 );

    String uuid = null;

    //first, check if user already did registration from that phone
    UserDbRecord userDbRecord = UserDAO.getInstance().getUserByPhone( user.phone );

    if( userDbRecord != null )
    {
        logger.info( "register. User already exist with phone: " + user.phone + ", id: " + userDbRecord.getId() );

        uuid = userDbRecord.getToken();
    }
    else
    {
        uuid = UUID.randomUUID().toString();
    }

    SMS.send( user.phone, random );

    Auth auth = new Auth();
    auth.token = uuid;

    return objectMapper.writeValueAsString( auth );
}

因此尝试执行以下操作:

public Mono<ServerResponse> register( ServerRequest request )
{
    Mono<User> user = request.bodyToMono( User.class );

    Mono<UserDbRecord> userDbRecord = user.flatMap( u -> Mono.just( userRepository.findByPhone( u.phone ) ) );

    int random = getRandomNumber( 111111, 999999 );

    String uuid = null;

    //first, check if user already did registration from that phone

    //now what???
    if( userDbRecord != null )
    {
        logger.info( "register. User already exist with phone: " + userDbRecord.getPhone() + ", id: " + userDbRecord.getId() );

        uuid = userDbRecord.getToken();
    }
    else
    {
        uuid = UUID.randomUUID().toString();
    }

    SMS.send( user.phone, random );

    Auth auth = new Auth();
    auth.token = uuid;

    return ok().contentType( APPLICATION_JSON ).syncBody( auth );
}

检查 userDbRecord Mono 是否为空以及从中提取电话属性的最佳方法是什么?

【问题讨论】:

标签: spring-boot spring-webflux


【解决方案1】:

重新思考数据处理方式

在使用 RxJava 或 Project Reactor 进行响应式编程时,从头到尾继续流程非常重要。

在您的情况下,您必须用响应式验证/检查替换命令式验证/检查:

public Mono<ServerResponse> register( ServerRequest request )
{
    return request
        .bodyToMono( User.class )
        // make sure you use Reactive DataBase Access in order to 
        // get the all benefits of Non-Blocking I/O with Project Reactor
        // if you use JPA - consider Moving to R2DBC r2dbc.io
        .flatMap( user -> // <1>
            Mono.just( userRepository.findByPhone( user.phone ) ) // <2>
                .map(userDbRecord -> {
                    logger.info( "register. User already exist with phone: " + userDbRecord.getPhone() + ", id: " + userDbRecord.getId() );
                    return userDbRecord.getToken();
                })
                .switchIfEmpty(Mono.fromSupplier(() -> UUID.randomUUID().toString())) <3>
                .flatMap(uuid -> {
                    SMS.send( user.phone, random ); <4>
                    Auth auth = new Auth();
                    auth.token = uuid;
                    return ok().contentType( APPLICATION_JSON ).syncBody( auth );
                })
        );
}

上面的示例展示了如何将命令式控制器的方法重写为响应式方法。我在下面放了几个 cmets 和描述:

  1. 这里我使用flatMap 以便在创建的闭包中保持对User 实体的访问。
  2. 确保您使用端到端的非阻塞、反应式 I/O -> 忽略此规则可能会导致否定所有 WebFlux 优势。如果您使用 JPA,请考虑迁移到 R2DBC 和 Spring Data R2DBC,它们为您提供 JPA 的反应式、非阻塞替代
  3. 频繁的 UUID 生成会导致线程阻塞 -> https://stackoverflow.com/a/14533384/4891253
  4. 确保这是非阻塞的

【讨论】:

  • 感谢您的解释。但是,在日食中,我收到了 SMS.send(user.phone, random); 行的错误。 - “无法解析用户”.. map/switchIfEmpty 将 Mono 转换为 Mono 后,用户引用是否会丢失?
猜你喜欢
  • 2019-02-23
  • 1970-01-01
  • 2020-10-17
  • 2021-01-28
  • 2019-07-23
  • 2017-10-14
  • 1970-01-01
  • 2018-10-07
  • 2020-07-29
相关资源
最近更新 更多