繁体   English   中英

如何返回 Mono<ServerResponse> (作为副作用?) Mono.subscribe()?

[英]How to return a Mono<ServerResponse> (as a side effect?) of Mono.subscribe()?

我有以下代码,它“有效”......到目前为止。 通过“有效”,我的意思是Flux<DemoPOJO>service.getAll()返回,并且“ hasElements().subscribe(this::foo) ”导致foo()生成正确反映是否Flux<DemoPOJO>有任何元素。

所需的最终状态是返回一个ServerResponse对象,包装Flux<DemoPOJO> ,它反映返回的 Flux 是空的还是“hasElements”。

我的问题是Mono.subscribe()返回一个reactor.core.Disposable ,我想以某种方式得到一个Mono<ServerResponse> 或者,我是“吠错树”了吗?

添加注意:我已经看到一些使用Flux.flatMap()例子,但是如果返回的 Flux 有很多元素,这似乎有问题(即检查hasElements()似乎比潜在地平面映射所有元素要好得多)。

@Component
public class DemoPOJOHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    private DemoPOJOService service;

    public Mono<ServerResponse> getAll(ServerRequest request) {
        Mono<ServerResponse> response = null;
        Flux<DemoPOJO>       entities = service.getAll();

        entities.hasElements().subscribe(this::foo);
        // just return something, for now
        return ServerResponse.ok().build();
    }

    private Mono<ServerRequest> foo(Boolean hasElements) {
        System.out.println("DEBUG >> Mono has elements -> " + hasElements);
        return Mono.empty();
    }
}

这是 DemoPOJOService 实现...

@Component
public class DemoPOJOService {

    @Autowired
    private DemoPOJORepo demoPOJORepo;

    public Flux<DemoPOJO> getAll() {
        return Flux.fromArray(demoPOJORepo.getAll());
    }

    // more implementation, omitted for brevity
}

而且,这里是 DemoPOJORepo 实现......

@Component
public class DemoPOJORepo {

    private static final int NUM_OBJS =20;

    private static DemoPOJORepo demoRepo = null;

    private Map<Integer, DemoPOJO> demoPOJOMap;

    private DemoPOJORepo() {
        initMap();
    }

    public static DemoPOJORepo getInstance() {
        if (demoRepo == null) {
            demoRepo = new DemoPOJORepo();
        }
        return demoRepo;
    }

    public DemoPOJO[] getAll() {
        return demoPOJOMap.values().toArray(new DemoPOJO[demoPOJOMap.size()]);
    }

    // more implementation, omitted for brevity

    private void initMap() {
        demoPOJOMap = new TreeMap<Integer, DemoPOJO>();

        for(int ndx=1; ndx<( NUM_OBJS + 1 ); ndx++) {
            demoPOJOMap.put(ndx, new DemoPOJO(ndx, "foo_" + ndx, ndx+100));
        }
    }
}

所以,我真的很想将先前的答案投反对票为“无响应”(因为我没有订阅Flux<DemoPOJO>实体”,而是订阅由'entities.hasElements()'产生的Mono 。而且,提供的“解决方案”并没有解决我对能够根据有/没有要返回的内容返回适当的ServerResponse的担忧。

然而,它确实让我进入了我认为解决我最初问题的“正确轨道”,所以......

我修改后的DemoPOJOHandler如下。 它似乎正确地返回,要么包装了“流量”service.getAll(返回ServerResponse.ok()),ServerResponse.noContent()如果通量是空的。

虽然这“有效”,并且似乎比我以前的要好得多,但非常感谢任何改进、评论或建议,因为我仍在尝试围绕 Reactor。

@Component
public class DemoPOJOHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    private DemoPOJOService service;

    public Mono<ServerResponse> getAll(ServerRequest request) {
        Flux<DemoPOJO> entities = service.getAll();

        return entities.hasElements().flatMap(hasElement -> {
            return hasElement ? ServerResponse.ok()
                                              .contentType(MediaType.APPLICATION_JSON)
                                              .body(entities, DemoPOJO.class)
                              : ServerResponse.noContent().build();
            });
    }
}

@SoCal 您的答案似乎有效,但它有一个缺点: getAll() DB 调用进行了两次。

困难在于您只能在开始接收数据后决定状态代码。

但由于您似乎并不真正需要主体的异步性质(您不是流式传输单个元素,而是生成一次性 JSON 响应),在这种情况下,您可以收集整个结果集并将其映射到响应.

所以调用数据库,收集Mono<List>的元素,将其map到 A) 404 空响应,如果列表为空,或者 B) 200 成功的 JSON 响应,否则(注意使用syncBody ):

@Component
public class DemoPOJOHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    private DemoPOJOService service;

    public Mono<ServerResponse> getAll(ServerRequest request) {
        Flux<DemoPOJO> entities = service.getAll();
        Mono<List<DemoPOJO>> collected = entities.collectList();

        return collected.map(list -> list.isEmpty() ? 
            ServerResponse.noContent().build() :
            ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .syncBody(list)
        );
    }
}

旁注:我认为ResponseEntity是带注释的控制器而不是ServerResponse的首选类型,请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-ann-响应实体

首先,您不负责订阅控制器中的通量。 获取数据并从控制器返回它只是整个管道的一小部分。 它基本上意味着您只需要提供业务逻辑,并且框架会向您的数据添加其他转换。 例如,它序列化响应,然后在完成后订阅它。

订阅业务代码中的flux意味着您启动了另一个管道,它可能完全独立于控制器返回的数据,但恰好在那里订阅了它。 如果你有相同的 Flux 并且你会在其他地方订阅它,结果将完全相同。

总结一下:您需要获取entities.hasElements() (即Mono<Boolean> )的返回值并将 bool 包装到响应中:

 public Mono<ServerResponse> getAll(ServerRequest request) {
        Mono<ServerResponse> response = null;
        Flux<DemoPOJO>       entities = service.getAll();

        return entities.hasElements()
           .flatMap(this::foo);

    }

    private Mono<ServerResponse> foo(Boolean hasElements) {
        System.out.println("DEBUG >> Mono has elements -> " + hasElements);
        return ServerResponse.ok().syncBody(hasElements);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM