如何在 Spring WebFlux 响应式方式的处理程序函数中使用 Mono 和 Flux



检查-->

我的模型看起来像这样。

@Document
public class PlanDetails {
@Id
private String id;
private String name;
private Double balance;
private Double internet;
private Date date;
--> //String of id's basically.
private List<String> members;
public PlanDetails(){}
public PlanDetails(String id, String name, Double balance, Double internet, Date date, List<String> members){
this.id = id;
this.name = name;
this.balance = balance;
this.internet = internet;
this.date = date;
this.members = members;
}
public String getId() {
return id;
}
/* Getter setters ommited for brevity */

这是我处理功能终结点的处理程序类。

package com.startelco.plandetailsapi.handler;
import com.startelco.plandetailsapi.model.PlanDetails;
import com.startelco.plandetailsapi.repository.PlanRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import static org.springframework.http.MediaType.APPLICATION_JSON;
@Component
public class PlanDetailsHandler {
private PlanRepository repository;

public PlanDetailsHandler(PlanRepository repository){
this.repository = repository;
}
//Get All Users
public Mono<ServerResponse> getAllUsers(ServerRequest request){
Flux<PlanDetails> users = repository.findAll();
return ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(users,PlanDetails.class);
}
--> //Get User by ID
public Mono<ServerResponse> getUserDetails(ServerRequest request){
String id = request.pathVariable("id");
Mono<PlanDetails> userMono = repository.findById(id);
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
return userMono.flatMap(user ->
ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject(user))
.switchIfEmpty(notFound)
);
}

//Create a user
public Mono<ServerResponse> saveUser(ServerRequest request){
Mono<PlanDetails> userMono = request.bodyToMono(PlanDetails.class);
return userMono.flatMap(user ->
ServerResponse.status(HttpStatus.CREATED)
.contentType(APPLICATION_JSON)
.body(repository.save(user),PlanDetails.class)
);
}

//Update user by ID
public Mono<ServerResponse> updateUser(ServerRequest request) {
String id = request.pathVariable("id");
Mono<PlanDetails> existingUserMono = this.repository.findById(id);
Mono<PlanDetails> userMono = request.bodyToMono(PlanDetails.class);
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
return userMono.zipWith(existingUserMono,
(user, existingUser) ->
new PlanDetails(existingUser.getId(), user.getName(), user.getBalance(), user.getInternet(),user.getDate(),user.getMembers())
)
.flatMap(user ->
ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(repository.save(user), PlanDetails.class)
).switchIfEmpty(notFound);
}

//Delete All Users
public Mono<ServerResponse> deleteAllUsers(ServerRequest request) {
return ServerResponse.ok()
.build(repository.deleteAll());
}
}

问题:通过重用以前编写的函数getUserDetails.getMemberDetails编码的反应式编码方式是什么?

要求。

所需功能:获取成员详细信息功能。

public Mono<ServerResponse> getMemberDetails(ServerRequest request) {
--> //Pseudocode
String id = request.pathVariable("id");
Mono<PlanDetails> userMono = repository.findById(id);
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
if(userMono.member is not null){
int length = userMono.member.length
Flux<PlanDetails> memberFlux;
for(int i=0;i<length;i++){
Mono<PlanDetails> member = getUserDetails(id=userMono.member[i]);
memberFlux.add(member);
}
}else{
return ServerResponse.ok().build(memberFlux=null or empty array);
}
return ServerResponse.ok().build(memberFlux.flatmap);
}

期望的行为

{
"id": "5b42ecc11cde674475cab39a",
"name": "Alex Svirsky",
"balance": 140,
"internet": 20,
"date": 1531107095659,
"members": [
"5b42ecdd1cde674475cab39b",
"5b42ed421cde674475cab39c",
"5b42ed5d1cde674475cab39d"
]
}

我的路由中的 REST 调用定义为http://localhost:8080/users/members/5b42ecc11cde674475cab39a

[    {
"id": "5b42ecdd1cde674475cab39b",
"name": "Bob Marley",
"balance": 120,
"internet": 9,
"date": 1531107095559,
"members": null
},
{
"id": "5b42ed421cde674475cab39c",
"name": "Charlie Sheen",
"balance": 10,
"internet": 9,
"date": 1531107095555,
"members": null
},
{
"id": "5b42ed5d1cde674475cab39d",
"name": "Dale Carnegie",
"balance": 100,
"internet": 9,
"date": 1531107055555,
"members": null
}
]

在我看来,第一种方法中没有太多可以重用的东西:由于这两种方法都返回一个完全成型的ServerResponse,你不能组成原件。这只是与一些样板repository.findById(),将其转换为ok响应或404响应......

因此,您真正需要的是一种在多次调用repository.findById之上撰写getMemberDetails的方法。如果我正确解释您的伪代码,您希望响应只是原始"用户"下所有"成员"的Flux<PlanDetail>(忽略有关所述原始用户的信息)?

您应该能够使用flatMap来反应性地执行此操作:

public Mono<ServerResponse> getMemberDetails(ServerRequest request) {
String id = request.pathVariable("id");
Mono<PlanDetails> userMono = repository.findById(id);
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
return userMono
//transform from user mono to Flux of member details
.flatMap(user -> Flux.fromArray(user.member)) //if `member` is an Iterable use the following instead:
//.flatMapIterable(user -> user.member)
//now we have a Flux of member IDs, go get details
.flatMap(repository::findById)
//this will naturally ignore not found members
//if no member is found or array of IDs is empty, the main sequence is itself empty at this point
.switchIfEmpty(notFound);
}

这种方法的唯一警告是,它不区分"未找到"(未找到原始用户)和"无内容"(用户没有可以找到的成员)。

我认为这终于对我有用了。如果我的伪代码不是很清楚,我很抱歉。感谢您@Simon巴塞尔的回答

public Mono<ServerResponse> getMemberDetails(ServerRequest request) {
String id = request.pathVariable("id");
Mono<PlanDetails> userMono = repository.findById(id);
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
Flux<PlanDetails> userFlux = userMono.flatMapIterable(user -> user.getMembers()).flatMap(repository::findById);
return ServerResponse.ok()
.contentType(APPLICATION_JSON)
.body(userFlux,PlanDetails.class);
}

最新更新