当我需要库函数的上下文和单声道响应时如何重构嵌套平面图?

How to refactor nested flatmaps when I need both context and mono response of a library function?

我有一个 响应式网络应用程序 (Spring WebFlux) 我通过 POST API 将用户个人资料图像存储在蔚蓝存储。如果不存在,我需要为用户创建一个存储桶。

服务层方法看起来像这样:(它包含嵌套的平面地图——这在 Reactive 应用程序中被认为是一种不好的做法,并且是一种代码味道。)我想重构出来,这样就有了没有嵌套的 flatMap。 有什么办法吗?

public Mono<BlockBlobItem> processAndUpload(FilePart filePart) {

    return Mono.subscriberContext().flatMap(context -> {
      String userId = context.get(USER_ID_CONTEXT);
      BlobContainerAsyncClient blobContainerClient = blobServiceAsyncClient.getBlobContainerAsyncClient(userId);

      return blobContainerClient.exists()
          .doOnEach(logOnNext(doesContainerExist -> {
            if (doesContainerExist) {
              LOGGER.info(STORAGE_CONTAINER_EXISTS_MSG);
            } else {
              LOGGER.info(STORAGE_CONTAINER_DOES_NOT_EXIST_MSG);
            }
          }))
          .doOnEach(logOnError(err -> LOGGER.error(CONTAINER_CHECK_FAILURE_MSG, err.getMessage(), err)))
          .flatMap(doesContainerExist -> {
            if (doesContainerExist) {
              return uploadFile(filePart, blobContainerClient, userId);
            } else {
              return blobContainerClient.createWithResponse(null, null)
                  .doOnEach(logOnComplete(response -> LOGGER.info(CONTAINER_CREATION_SUCCESS_MSG)))
                  .doOnEach(logOnError(err -> LOGGER.error(CONTAINER_CREATION_FAILURE_MSG, err.getMessage(), err)))
                  .then(uploadFile(filePart, blobContainerClient, userId));
            }
          });
    });
  }

恐怕嵌套 flatMap 是唯一的方法,只要您需要这两个上下文。

如果您谈论重构,我会将 lambda 表达式(或至少它们的右侧)移出方法以实现可读性。还可以考虑先使用 map 来获得 userId,只要您不需要初始的 context.

public Mono<BlockBlobItem> processAndUpload(FilePart filePart) {

    return Mono.subscriberContext()
        .map(context -> context.get(USER_ID_CONTEXT))
        .flatMap(userId -> {
                var client = blobServiceAsyncClient.getBlobContainerAsyncClient(userId);
                return client.exists()
                    .doOnEach(logOnNext(doesContainerExistLambda))
                    .doOnEach(logOnError(errLambda))
                    .flatMap(doesExist -> existenceHandler(filePart, client, userId));
                }
        );
}

名为 doesContainerExistLambdaerrLambdaexistenceHandler 的方法和 lambda 表达式是根据您的需要和考虑进行更改的主题。代码片段的重点是突出显示可以移动到其他地方的内容。