当我需要库函数的上下文和单声道响应时如何重构嵌套平面图?
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));
}
);
}
名为 doesContainerExistLambda
、errLambda
、existenceHandler
的方法和 lambda 表达式是根据您的需要和考虑进行更改的主题。代码片段的重点是突出显示可以移动到其他地方的内容。
我有一个 响应式网络应用程序 (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));
}
);
}
名为 doesContainerExistLambda
、errLambda
、existenceHandler
的方法和 lambda 表达式是根据您的需要和考虑进行更改的主题。代码片段的重点是突出显示可以移动到其他地方的内容。