反应式Spring引导:返回在映射查找之前计算
我正在使用反应式WebClient构建一个与其他两个API通信的API。API2需要从API1获取信息,然后我的服务组合并返回这两个信息。 资源:反应式Spring引导:返回在映射查找之前计算,spring,spring-webflux,spring-webclient,spring-reactive,Spring,Spring Webflux,Spring Webclient,Spring Reactive,我正在使用反应式WebClient构建一个与其他两个API通信的API。API2需要从API1获取信息,然后我的服务组合并返回这两个信息。 资源: @GetMapping("monoMedication/{medID}") public Mono<Object> getMonoMedication(@PathVariable String medID) throws SSLException { Mono<Login>
@GetMapping("monoMedication/{medID}")
public Mono<Object> getMonoMedication(@PathVariable String medID) throws SSLException {
Mono<Login> Login =createWebClient()
.post()
.uri("URI_LOGIN_API1" )
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(body))
.retrieve()
.bodyToMono(Login.class);
return Login.map(login-> {
Mono<String> medicationBundles = null;
try {
medicationBundles = createWebClient()
.post()
.uri("URI_API1_GET_DATA")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject("Information"))
.header("Authorization", login.getSessionId())
.retrieve()
.bodyToMono(String.class);
} catch (SSLException e) {
e.printStackTrace();
}
return medicationBundles.map(bundles_string -> {
try {
List<Object> bundle_list = mapper.readValue(bundles_string, new TypeReference<List<Object>>(){});
bundle_list.forEach(bundle-> processBundle(bundle,medicationList));
return medicationList;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
})
})
}
@GetMapping(“单药/{medID}”)
公共Mono GetMonoMediation(@PathVariable String medID)引发SSLexException{
Mono Login=createWebClient()
.post()
.uri(“uri\u LOGIN\u API1”)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(body))
.retrieve()
.bodyToMono(Login.class);
返回Login.map(登录->{
单药束=null;
试一试{
medicationBundles=createWebClient()
.post()
.uri(“uri\u API1\u GET\u数据”)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(“信息”))
.header(“授权”,login.getSessionId())
.retrieve()
.bodyToMono(String.class);
}捕获(SSE){
e、 printStackTrace();
}
返回medicationBundles.map(bundles\u string->{
试一试{
List bundle\u List=mapper.readValue(bundles\u string,new TypeReference(){});
bundle_list.forEach(bundle->processBundle(bundle,medicationList));
返回药物清单;
}捕获(JsonProcessingException e){
e、 printStackTrace();
}
返回null;
})
})
}
职能:
List<String> medicationList = new ArrayList<>();
private void processBundle(Object bundle, List<String> medicationlist) {
//do something to get id from bundle
String ID = bundle.getID();
// if i add something to medicationList.add(ID) here, it is in the required return of my API
Mono<String> Medication =
webClientBuilder.build()
.get()
.uri("URI_API2_GET_DATA"+ID)
.retrieve()
.bodyToMono(String.class);
Medication.map(medication_ID -> {
//do something to get information from medication_ID
String info = medication_ID.getInfo();
//this Information comes after the required return
return medicationList.add(info+ID);
}).subscribe();
}
List medicationList=new ArrayList();
私有void processBundle(对象bundle、列表medicationlist){
//做些什么从包中获取id
String ID=bundle.getID();
//如果我在这里向medicationList.add(ID)添加了一些内容,它将在API的必需返回中
单一药物=
webClientBuilder.build()
.get()
.uri(“uri\u API2\u GET\u DATA”+ID)
.retrieve()
.bodyToMono(String.class);
药物治疗图(药物治疗ID->{
//采取措施从药物ID获取信息
String info=medicing_ID.getInfo();
//此信息在要求的返回之后提供
返回药物列表。添加(信息+ID);
}).subscribe();
}
我的问题是,返回在所需的最后一个映射完成之前。我不知怎么错过了什么。我在不同的位置尝试了不同的方法,例如,then(),然后many(),然后return()。
有办法做到这一点吗?如果有一个可能已经完成的简单示例,那也会有帮助 在代码中很难遵循,因为您正在以非最佳实践的方式混合和匹配反应式编程和命令式编程 您的代码没有编译,并且有一些奇怪的东西,比如从未使用过
medID
,变量也从未声明过,比如body
。因此,我只是“照原样”使用您的代码,我并没有生成一个完全有效的示例,只是一个指南
你应该选择反应路线或命令路线。如果以后有人抱怨,我的回答中的某些部分将是自以为是的,所以这是免责声明
首先,您在每个请求上都创建了几个webclient
,我认为这是一种不好的做法。创建WebClient
是一种不必要的昂贵操作,因为您可以重用它们,因此您应该在启动期间声明web客户端,并在中声明它们
@Configuration
public class WebClientConfig {
@Bean
@Qualifier("WebClient1")
public WebClient createWebClient1() {
return WebClient.create( ... );
}
@Bean
@Qualifier("WebClient2")
public WebClient createWebClient2() {
return WebClient.create( ... );
}
@Bean
@Qualifier("WebClient3")
public WebClient createWebClient3() {
return WebClient.create( ... );
}
}
然后通过将它们自动关联到类中来使用它们
在清理代码并将其划分为函数之后,我希望这能让您了解如何构造它。您的问题是您没有正确地从函数返回,并且没有链接到返回。一旦你需要使用订阅
你通常就会知道你做错了什么
@RestController
public class FooBar {
private WebClient webClient1;
private WebClient webClient2;
private WebClient webClient3;
@Autowire
public Foobar(@Qualifier("WebClient1") WebClient webclient1, @Qualifier("WebClient2") WebClient webclient2, @Qualifier("WebClient3") WebClient webclient3) {
this.webClient1 = webClient1;
this.webClient2 = webClient2;
this.webClient3 = webClient3;
}
@GetMapping("monoMedication/{medID}")
public Mono<List<MedicationData>> getMonoMedication(@PathVariable String medID) {
return doLogin()
.flatMap(login -> {
return getMedicationBundles(login.getSessionId());
}).flatMap(medicationBundles -> {
return getMedicationData(medicationBundle.getId());
}).collectList();
}
private Mono<Login> doLogin() {
return webClient1
.post()
.uri("URI_LOGIN_API1")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(body)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> ...)
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(Login.class);
}
private Flux<MedicationBundle> getMedicationBundles(String sessionId) {
return webClient2
.post()
.uri("URI_API1_GET_DATA")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue("Information")
.header("Authorization", sessionId)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> ...)
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToFlux(MedicationBundle.class);
}
private Mono<String> getMedicationData(String medicationId) {
return webClient3.get()
.uri(uriBuilder - > uriBuilder
.path("/URI_API2_GET_DATA/{medicationId}")
.build(medicationId))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> ...)
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(MedicationData.class);
}
}
@RestController
公共级FooBar{
私有网络客户端网络客户端1;
私有网络客户端网络客户端2;
私有网络客户端网络客户端3;
@自动连线
public Foobar(@Qualifier(“WebClient1”)WebClient1、@Qualifier(“WebClient2”)WebClient2、@Qualifier(“WebClient3”)WebClient3){
this.webClient1=webClient1;
this.webClient2=webClient2;
this.webClient3=webClient3;
}
@GetMapping(“单药/{medID}”)
公共Mono GetMonoMedical(@PathVariable String medID){
返回多洛金()
.flatMap(登录->{
返回getMedicationBundles(login.getSessionId());
}).flatMap(药物束->{
返回getMedicationData(medicationBundle.getId());
}).collectList();
}
私有单多洛金(){
返回WebClient 1
.post()
.uri(“uri\u LOGIN\u API1”)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body值(body)
.retrieve()
.onStatus(HttpStatus::is4xxClientError,响应->…)
.onStatus(HttpStatus::is5xxServerError,响应->…)
.bodyToMono(Login.class);
}
私有流量GetMedicalationBundles(字符串sessionId){
返回网络客户端2
.post()
.uri(“uri\u API1\u GET\u数据”)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(“信息”)
.标题(“授权