异步API端点Spring Webflux

3
我需要编写Spring Webflux端点(路由器函数),以便向一组邮件接收者发送电子邮件。用户界面将选择邮件接收者列表并将其发送到我编写的API。我希望实现这个端点的方式是,一旦我收到请求,就立即向用户界面发送响应,表示正在发送电子邮件。发送响应后,我应该继续异步进行邮件发送工作。我不能像在Spring MVC中使用@async注释一样使用它,因为在反应式世界中,这是反模式。
由于我正在使用Spring Webflux开发API,我应该如何发送响应?
我的代码中有以下结构:
Router.java
@Bean
public RouterFunction<ServerResponse> sendEmail() {
 return route(POST("/email").and(accept(APPLICATION_JSON)), handler::sendEmail);
}

Handler.java

@Autowired
EmailService emailService;

public Mono<ServerResponse> sendEmail(ServerRequest request) {
    Mono<PojoA> pojoAMono = request.bodyToMono(PojoA.class);
    return pojoAMono.flatMap(pojoA -> {
       return emailService.sendEmail(pojoA).flatMap(mailSent -> {
         return  ServerResponse
        .status(HttpStatus.OK)
        .contentType(MediaType.APPLICATION_JSON)
        .body("Mails are being sent", String.class));
       });
    });
    
}
2个回答

0

你应该构建响应,然后处理数据(发送电子邮件)。

就像这样:

@Bean
public RouterFunction<ServerResponse> sendEmail() {
    return route(POST("/test").and(accept(APPLICATION_JSON)), this::someMethod);
}

Mono<ServerResponse> someMethod(ServerRequest serverRequest) {
    return ServerResponse.ok().build()
            .doOnNext(r -> Mono.just("data") //doing some process like send email
                    .delayElement(Duration.ofSeconds(2))
                    .subscribeOn(Schedulers.parallel())
                    .log()
                    .subscribe());
}

为了测试目的,我加了一个延迟,以便在响应发送后看到数据处理。

0
你可以直接将响应返回给调用者,然后在流完成之后运行电子邮件发送作为副作用。这可以通过在流完成后执行的doFinally来实现。
因此,您的代码可能类似于以下内容:
public Mono<ServerResponse> sendEmail(ServerRequest request) {
    return request.bodyToMono(PojoA.class)
            .map(this::sendEmailSideEffect)
            .flatMap(pojoA -> ServerResponse
                    .status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body("Mails are being sent", String.class));
}

private Mono<PojoA> sendEmailSideEffect(PojoA pojoA) {
    return Mono.just(pojoA)
            .doFinally(signalType -> emailService.sendEmails(pojoA));
}

我尝试了上面的代码,当我测试它时,似乎它仍然会等待sendMailSideEffect完成,然后才会响应调用者。 - Ashok B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接