Spring WebFlux - 如何从请求中获取数据?
Spring WebFlux - how to get data from request?
尝试将我的 Spring 启动应用程序迁移到 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 是否为空以及如果不为空从中提取 phone 属性 的最佳方法是什么?
重新思考数据处理方式
在使用 RxJava 或 Project Reactor 的响应式编程中,从头到尾继续您的流程非常重要。
在您的情况下,您必须将命令式 validations/checks 替换为反应式
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 );
})
);
}
以上示例展示了如何将命令式控制器的方法重写为反应式方法。我在下面对它们进行了一些评论和描述:
- 这里我使用
flatMap
以便在创建的闭包中保持对 User
实体的访问。
- 确保从头到尾都使用非阻塞、反应式 I/O -> 忽略此规则可能会导致否定所有 WebFlux 的好处。如果您使用 JPA,请考虑转向 R2DBC 和 Spring Data R2DBC,它为您提供了 JPA
的反应式、非阻塞替代品
- 频繁生成 UUID 会导致线程阻塞 ->
- 确保这是非阻塞的
尝试将我的 Spring 启动应用程序迁移到 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 是否为空以及如果不为空从中提取 phone 属性 的最佳方法是什么?
重新思考数据处理方式
在使用 RxJava 或 Project Reactor 的响应式编程中,从头到尾继续您的流程非常重要。
在您的情况下,您必须将命令式 validations/checks 替换为反应式
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 );
})
);
}
以上示例展示了如何将命令式控制器的方法重写为反应式方法。我在下面对它们进行了一些评论和描述:
- 这里我使用
flatMap
以便在创建的闭包中保持对User
实体的访问。 - 确保从头到尾都使用非阻塞、反应式 I/O -> 忽略此规则可能会导致否定所有 WebFlux 的好处。如果您使用 JPA,请考虑转向 R2DBC 和 Spring Data R2DBC,它为您提供了 JPA 的反应式、非阻塞替代品
- 频繁生成 UUID 会导致线程阻塞 ->
- 确保这是非阻塞的