Spring-Webflux: 从 Mono 中提取对象,无需使用 block() 方法

huangapple go评论94阅读模式
英文:

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&lt;ServerResponse&gt; routes(UserHandler handler){
return RouterFunctions
.route(POST(&quot;/rest/create&quot;),
handler::createUser);
}
} 

Handler

@Component
public class UserHandler {
private UserService service;
public UserHandler(UserService service) {
this.service = service;
}
public Mono&lt;ServerResponse&gt; saveUser(ServerRequest request) 
{
Mono&lt;User&gt; 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))

如果您对 mapflatMap 有兴趣,可以查看这个 StackOverflow 问题

英文:

If you're willing to have Person p processed in a Mono-Lambda, then you can try

public Mono&lt;ServerResponse&gt; saveUser(ServerRequest request) 
{
// Mono&lt;User&gt; user = request.bodyToMono(User.class)
request.bodyToMono(User.class)
// Convert a Mono&lt;User&gt; to a Mono&lt;Person&gt;    
.map((User user1) -&gt; getPersonFromUser(user))
.map((Person p) -&gt; {
// 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) -&gt; 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) -&gt; getPersonFromUser(user))

you would use

.flatMap((User user1) -&gt; getPersonFromUser(user))

You can checkout this StackOverFlow Question if you're interested in map vs flatmap

huangapple
  • 本文由 发表于 2020年7月27日 06:31:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/63106428.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定