英文:
Spring-Webflux: Extracting Object from Mono without block()
问题
我是新的Spring Webflux。我正在编写一个简单的API,该API调用另一个API并返回响应。
我遇到的问题是,我的API接收的请求类型与外部API不同。我必须转换传入的请求以发送到外部API。我正在使用Mono<T>来接收我的API的请求,但在不使用block()的情况下很难转换为另一个对象。
**输入**
**路由器**
@Configuration
@EnableWebFlux
public class RouterConfig implements WebFluxConfigurer{
@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler){
return RouterFunctions
.route(POST("/rest/create"),
handler::createUser);
}
}
**处理器**
@Component
public class UserHandler {
private UserService service;
public UserHandler(UserService service) {
this.service = service;
}
public Mono<ServerResponse> saveUser(ServerRequest request)
{
Mono<User> user = request.bodyToMono(User.class)
/* 目前我正在使用block来获取User对象 */
User user1 = user.block()
/* 转换user为person */
Person p =getPersonFromUser(user);
}
}
**POJO类**
class User
{
private String name;
private String id;
private String email;
private String phone;
}
class Person
{
private String email;
/* id和name的组合 */
private String accountNumber;
private String phone;
}
是否有一种方法可以在不阻塞的情况下将Mono<User>转换为Person对象?
英文:
I am new Spring Webflux. I am writing a simple api which call another api and returns response.
The problem I have is my api takes diffrent type of request than the external api.I have to convert the incoming request to send to external api.I am using Mono<T> to receive request for my api, but having trouble to convert to another object without block().
Input
Router
@Configuration
@EnableWebFlux
public class RouterConfig implements WebFluxConfigurer{
@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler){
return RouterFunctions
.route(POST("/rest/create"),
handler::createUser);
}
}
Handler
@Component
public class UserHandler {
private UserService service;
public UserHandler(UserService service) {
this.service = service;
}
public Mono<ServerResponse> saveUser(ServerRequest request)
{
Mono<User> user = request.bodyToMono(User.class)
/* currently I am using block to get User object */
User user1 = user.block()
/* convert user to person */
Person p =getPersonFromUser(user);
}
Pojos
class User
{
private String name;
private String id;
private String email;
private String phone;
}
class Person
{
private String email;
/* Combination of id and name */
private String accountNumber;
private String phone;
}
Is there a way I can convert the Mono<User> to Person object without blocking?
答案1
得分: 4
如果您愿意在 Mono-Lambda 中处理 Person p,那么您可以尝试以下代码:
public Mono<ServerResponse> saveUser(ServerRequest request)
{
// Mono<User> user = request.bodyToMono(User.class)
request.bodyToMono(User.class)
// 将 Mono<User> 转换为 Mono<Person>
.map((User user1) -> getPersonFromUser(user))
.map((Person p) -> {
// 代码,可以返回 ServerResponse 对象或中间对象
})
// 根据需要添加其他代码
因为 request.bodyToMono(User.class) 返回一个 User 的 Mono,您可以调用该 Mono 的 map 方法。map 方法接受一个类型为 Function 的 Lambda,该 Lambda 接受一个参数,返回一个不同类型的对象。
第一个 map 调用:
.map((User user1) -> getPersonFromUser(user))
提供了一个 Lambda,该 Lambda 接受一个将 User 转换为 Person 的 Function,因此我从一个 "Mono for User" 跳转到了一个 "Mono for Person"。
我不知道是否有一种直接从 Person 获取 ServerResponse 的方法,但在第二个 map 调用中,您可以编写一个返回 ServerResponse 的函数(在这种情况下,您将拥有 "Mono of a ServerResponse"),或者返回另一个中间对象。如果选择后者,可能需要进行额外的映射调用。
注意:如果在 Lambda 内部获取到一个 Mono,您应该使用 flatMap 方法,即如果 getPersonFromUser(user) 返回的是 Person 的 Mono 而不是一个 Person,那么您应该使用:
.flatMap((User user1) -> getPersonFromUser(user))
如果您对 map 和 flatMap 有兴趣,可以查看这个 StackOverflow 问题。
英文:
If you're willing to have Person p processed in a Mono-Lambda, then you can try
public Mono<ServerResponse> saveUser(ServerRequest request)
{
// Mono<User> user = request.bodyToMono(User.class)
request.bodyToMono(User.class)
// Convert a Mono<User> to a Mono<Person>
.map((User user1) -> getPersonFromUser(user))
.map((Person p) -> {
// Code that either returns ServerResponse object or an intermediary object
})
// Additional code as needed
Because request.bodyToMono(User.class) returns a Mono of a User, you can call that Mono's map method. the map method takes in a lambda of type Function which takes in a parameter of one type and returns an object of a different type.
The first map call made:
.map((User user1) -> getPersonFromUser(user))
is given a Lambda that takes in a Function that converts a User to a Person, hence I jumped from having a "Mono for User" to a "Mono for Person".
I don't know if there is a way to get a ServerResponse directly from Person but in the second map call, you can write the function to return a ServerResponse (in which case you have a "Mono of a ServerResponse" and you're basically done) or return another intermediary object. If you do the latter, you'll likely need additional mapping calls.
Note: If within your Lambda, you get a Mono, you'll want to use the flatMap method, i.e. if getPersonFromUser(user) returns a Mono of a Person instead of a Person, then instead of
.map((User user1) -> getPersonFromUser(user))
you would use
.flatMap((User user1) -> getPersonFromUser(user))
You can checkout this StackOverFlow Question if you're interested in map vs flatmap
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论