函数需要做两件事情,根据请求vo里的url字段,下载2个图片。调用myService的方法,将结果填在返回vo里。使用Webflux的webclient
三种方法的共同代码:
private void writeRecord(String logId, String f1Url, String f2Url, Float similarity) {
IdentityEntity e = new IdentityEntity();
e.setF1Url(f1Url);
e.setF2Url(f2Url);
e.setSimilarity(similarity);
e.setLogId(logId);
this.repository.save(e);
}
方法一的共同代码:
private Mono<ClientResponse> getImage(String url) {
return webClient.get()
.uri(url)
.exchange();
}
方案一、下载图片1,如果成功,再下载图片2。都下载之后进行处理。
@Override
public Mono<IdentityResponseVo> compare(Mono<IdentityRequestVo> vo) {
return vo.flatMap(v -> {
Mono<ClientResponse> r1 = getImage(v.getF1Url());
Mono<IdentityResponseVo> map = r1.flatMap(clientResponse -> {
if (!clientResponse.statusCode().is2xxSuccessful()) {
return Mono.just(new IdentityResponseVo(ERR_DOWNLOAD, v.getLogId()));
} else {
Mono<ClientResponse> r2 = getImage(v.getF2Url());
Mono<IdentityResponseVo> map1 = r2.flatMap(clientResponse2 -> {
if (!clientResponse2.statusCode().is2xxSuccessful()) {
return Mono.just(new IdentityResponseVo(ERR_DOWNLOAD, v.getLogId()));
} else {
// Convert first image to base64
Mono<String> f1Base64Mono = r1.flatMap(response -> response.bodyToMono(byte[].class))
.map(Base64::encodeAsString);
// Convert second image to base64
Mono<String> f2Base64Mono = r2.flatMap(response -> response.bodyToMono(byte[].class))
.map(Base64::encodeAsString);
Mono<AiIdentity> aiIdentityMono = f1Base64Mono.flatMap(f1Base64 ->
f2Base64Mono.map(f2Base64 -> myService.handle(f1Base64, f2Base64))
.doOnNext(ret -> this.writeRecord(v.getLogId(), v.getF1Url(), v.getF2Url(), ret.getSimilarity())));
return aiIdentityMono.map(ret -> IdentityResponseVo.transform(ret, v.getLogId()));
}
});
return map1;
}
});
return map;
});
}
方案二、下载两个图片,如果都是2xx才会进行处理,否则返回错误:
@Override
public Mono<IdentityResponseVo> compare2(Mono<IdentityRequestVo> vo) {
return vo.flatMap(v -> {
Mono<ClientResponse> r1 = getImage(v.getF1Url());
Mono<ClientResponse> r2 = getImage(v.getF2Url());
Mono<Boolean> both2xx = Mono.zip(r1.map(ClientResponse::statusCode), r2.map(ClientResponse::statusCode))
.map(statusCode -> {
log.info("{} is error: {} and {} is error: {}",
v.getF1Url(), statusCode.getT1().is2xxSuccessful(),
v.getF2Url(), statusCode.getT2().is2xxSuccessful());
return statusCode.getT1().is2xxSuccessful() && statusCode.getT2().is2xxSuccessful();
});
return both2xx.flatMap(received -> {
if (received) {
// Convert first image to base64
Mono<String> f1Base64Mono = r1.flatMap(response -> response.bodyToMono(byte[].class))
.map(Base64::encodeAsString);
// Convert second image to base64
Mono<String> f2Base64Mono = r2.flatMap(response -> response.bodyToMono(byte[].class))
.map(Base64::encodeAsString);
Mono<AiIdentity> aiIdentityMono = f1Base64Mono.flatMap(f1Base64 ->
f2Base64Mono.map(f2Base64 -> myService.handle(f1Base64, f2Base64))
).doOnNext(ret -> this.writeRecord(v.getLogId(), v.getF1Url(), v.getF2Url(), ret.getSimilarity()));
return aiIdentityMono.map(ret -> IdentityResponseVo.transform(ret, v.getLogId()));
} else {
// Return default JSON if any of the images were not received successfully
return Mono.just(new IdentityResponseVo(ERR_DOWNLOAD, v.getLogId()));
}
});
});
}
方案三、“同时”下载图片1和2,通过onErrorReturn,处理任何一个图片响应不是2xx的情况
如果下载图片响应不是404,会得到Mono.error, WebResponseException,这时onErrorReturn就会执行。如果响应404,Controller层直接返回,没有任何的body或者日志。那是因为Mono.empty,终止了整个数据流。
private Mono<String> getImageByUrl(String url) {
Mono<byte[]> mono = webClient.get()
.uri(url)
.retrieve()
.bodyToMono(byte[].class)
.onErrorResume(WebClientResponseException.class,
ex -> ex.getRawStatusCode() == 404 ? Mono.empty() : Mono.error(ex));
return mono.map(Base64::encodeAsString);
}
@Override
public Mono<IdentityResponseVo> compare(Mono<IdentityRequestVo> vo) {
return vo.flatMap(v -> {
Mono<String> f1Base64Mono = getImageByUrl(v.getF1Url());
Mono<String> f2Base64Mono = getImageByUrl(v.getF2Url());
Mono<AiIdentity> aiIdentityMono = f1Base64Mono.flatMap(f1Base64 ->
f2Base64Mono.map(f2Base64 -> myService.handle(f1Base64, f2Base64))
).doOnNext(ret -> this.writeRecord(v.getLogId(), v.getF1Url(), v.getF2Url(), ret.getSimilarity()));
return aiIdentityMono.map(ret -> IdentityResponseVo.transform(ret, v.getLogId()))
.onErrorReturn(new IdentityResponseVo(ResponseState.ERR_DOWNLOAD, v.getLogId()));
});
}