如何使用 Spring Webflux Reactive Java 将多个 Mono 映射到一个对象中?

问题描述

我想知道将多个响应式服务响应映射或合并到一个唯一对象中的正确或最佳方法是什么。

例如,简单的传统代码如下:

public UserProfile getUserProfile(String id){
    User user = userService.getUser(id);
    Messages messages = messageService.getMessagesFromUser(id);
    Notifications notifications = notificationService.getNotificationsForUser(id);
    return new UserProfile(user,message,notifications);
}

当尝试使用 webflux 将它写得更“功能性”时,它看起来像这样:

public Mono<UserProfile> getUserProfile(String id){
   return userService.getUser(id)
          .map( user -> {
                return messageService.getMessagesFromUser(id)
                     .map(messages -> {
                           return notificationService.getNotificationsForUser(id)
                                  .map(notifications -> new UserProfile(user,notifications))
                       }
            }
}

我个人不喜欢这种“映射步骤”,因为它不是顺序转换。我需要更多类似的并行处理,使用 CompletableFuture 或其他多线程框架和传统的命令式代码(非功能性)非常容易实现。

您认为如何改进此实施? 这段代码工作正常,但我认为这不是编写它的正确方法。在我看来,它看起来很丑,不太好理解。

编辑!!! 我想我已经找到了使用 Mono.zip 的更好方法,但我仍然认为它应该可以改进

@GetMapping("v1/event/validate/")
public Mono<PanoramixscoreDetailDTO> validateEvent(@RequestBody LeadEventDTO eventDTO) {
    return leadService.getLead(eventDTO.getSiteId(),eventDTO.getIdContacto())
            .flatMap(lead -> {
                Mono<PhoneValidationDTO> phoneValidation = validationService.validatePhone(eventDTO.getSiteId(),lead.getPhone());
                Mono<EmailValidationDTO> emailValidation = validationService.validateEmail(eventDTO.getSiteId(),lead.getLeadUser().getEmail());
                Mono<ProcessedProfileSmartleadDTO> smartleadProfile = smartleadService.getProcessedProfile(eventDTO.getSiteId(),eventDTO.getIdUsuario());
                return Mono.zip(phoneValidation,emailValidation,smartleadProfile)
                        .map(tuple -> panoramixscoreMapper.mapTo(lead,tuple.getT1(),tuple.getT2(),tuple.getT3(),eventDTO));
            });
}

我想听听您的意见。 谢谢!

解决方法

Mono.zip() 是可行的方法,但您可以通过使用覆盖来节省一步,该覆盖允许您一次性指定压缩发布者和地图功能:

@GetMapping("v1/event/validate/")
public Mono<PanoramixScoreDetailDTO> validateEvent(@RequestBody LeadEventDTO eventDTO) {
    return leadService.getLead(eventDTO.getSiteId(),eventDTO.getIdContacto())
            .flatMap(lead ->
                    Mono.zip(arr ->
                                    panoramixScoreMapper.mapTo(lead,(PhoneValidationDTO) arr[0],(EmailValidationDTO) arr[1],(ProcessedProfileSmartLeadDTO) arr[2],eventDTO),validationService.validatePhone(eventDTO.getSiteId(),lead.getPhone()),validationService.validateEmail(eventDTO.getSiteId(),lead.getLeadUser().getEmail()),smartleadService.getProcessedProfile(eventDTO.getSiteId(),eventDTO.getIdUsuario()))

            );
}