java - 如何使用 Spring WebFlux Reactive 方式在处理函数中使用 Mono 和 Flux

标签 java spring spring-webflux project-reactor java-10

检查 -->

我的模型看起来像这样。

@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 的 Reactive 方法是什么?

Requirement.

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

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回应...

所以你真正需要的是一种编写getMemberDetails的方法在对 repository.findById 的许多调用之上.如果我正确解释你的伪代码,你希望响应只是一个 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);
}

此方法唯一需要注意的是,它不区分“未找到”(未找到原始用户)与“无内容”(用户没有可以找到的成员)。

关于java - 如何使用 Spring WebFlux Reactive 方式在处理函数中使用 Mono 和 Flux,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51243415/

相关文章:

java - 为具有泛型类型的 Java POJO 生成 Avro 架构

javascript - Axios POST 请求 : Content-type is set, 但在 spring 内它是空的

java - Spring Stomp over Websocket : Message/Buffer/Cache/Stream limits

java - Spring WebFilter覆盖ExceptionHandler header

java - 为什么在重写 toString 方法时需要 public 修饰符?

java - 将数据从 java 程序存储到 MySQL 的最简单方法是什么?

java - 如何针对 gradle 项目中某种类型的所有文件运行 java 方法?

java - 如何在 spring mvc 中对特定请求执行过滤器?

spring - 未抛出 spring webflux 的自定义异常

spring - 无法在 react 测试中初始化 'javax.el.ExpressionFactory'