问题的解释有点长。请花一点时间帮忙!
我有两个 http 调用,它们将提供以下数据。
第一个 http 请求调用将返回 <Mono<List<Chips>>
[
{
"id": 1,
"name": "redlays"
},
{
"id": 2,
"name": "yellowlays"
},
{
"id": 3,
"name": "kurkure"
}
]
Chips
模型是
@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Chips {
private int id;
private String name;
}
第二个 http 请求调用将根据 Mono<ChipsDetails>
Id
{
"id": 1,
"color": "red",
"grams": "50"
}
ChipsDetails
模型如下,
@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ChipsDetails {
private int id;
private String color;
private String grams;
}
我已经使用 Webflux 完成了实现。这里我使用了三个模型,分别是 Chips
、ChipsDetails
和 ChipsFullDetails
。
模型 Chips
将具有两个属性 id
和 name
然后模型 ChipsDetails
将具有三个属性 id
、color
和 {{1 }} 而模型 grams
将具有 ChipsFullDetails
和 Chips
属性的组合,它们是 ChipsDetails
、id
、name
和 color
grams
此处 @RestController
@RequestMapping("/chips")
public class ChipsController {
@Autowired
ChipsService chipsService;
@GetMapping
public Mono<List<ChipsFullDetails>> getAllChips() {
return chipsService.getChips()
.map(f -> {
List<ChipsFullDetails> chipsFullDetails = new ArrayList<>();
f.forEach(a -> {
ChipsFullDetails chipsFullDetail = new ChipsFullDetails();
chipsFullDetail.setId(a.getId());
chipsFullDetail.setName(a.getName());
chipsService.getChipsDetails(a.getId())
.subscribe(b -> {
chipsFullDetail.setColor(b.getColor());
chipsFullDetail.setGrams(b.getGrams());
});
chipsFullDetails.add(chipsFullDetail);
});
return chipsFullDetails;
}
);
}
}
将返回 chipsService.getChips()
这是第一次调用,Mono<List<Chips>>
将返回 chipsService.getChipsDetails(a.getId())
这是第二次 http 请求调用。
执行的结果将是 Mono<ChipsDetails>
ChipsFullDetails
问题是 @Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ChipsFullDetails {
private int id;
private String name;
private String color;
private String grams;
}
为 ChipsFullDetails
和 color
属性返回 null,即使它是在内部订阅的,我们也可以从第二个 http 调用中获取这些属性。
如何以异步方式实现第二次 Http 调用即 grams
取决于第一个 http 调用(chipsService.getChipsDetails(a.getId())
)的结果?
这是否可以在不阻塞两个调用的情况下实现?
答案 0 :(得分:4)
我会先将初始 Mono<List<Chips>>
转换为 Flux<Chips>
,以便您可以在每个元素上 flatMap
,例如类似的东西:
public Mono<List<ChipsFullDetails>> getAllChips() {
return chipsService
.getChips()
// Mono<List> to Flux:
.flatMapIterable(Function.identity())
// flat map on each element:
.flatMap(this::buildChipsFullDetails)
// Flux back to Mono<List>:
.collectList();
}
private Mono<ChipsFullDetails> buildChipsFullDetails(Chips chips) {
return chipsService
.getChipsDetails(chips.getId())
// once you get both chips and details, aggregate:
.map(details -> buildChipsFullDetails(chips, details));
}
private ChipsFullDetails buildChipsFullDetails(Chips chips, ChipsDetails details) {
// straightforward synchronous code:
ChipsFullDetails chipsFullDetail = new ChipsFullDetails();
chipsFullDetail.setId(chips.getId());
chipsFullDetail.setName(chips.getName());
chipsFullDetail.setColor(details.getColor());
chipsFullDetail.setGrams(details.getGrams());
return chipsFullDetail;
}
答案 1 :(得分:0)
我基本上不同意使用 Flux
的想法,但我承认我也有。
我想说的是,如果您想获取芯片列表的详细信息,那么您应该创建一个端点来执行此操作。那么这将是一个单一的调用。
对于你原来的问题,有一种方法可以不用 Flux
,但它读起来有点搞笑:
ParameterizedTypeReference<List<Chip>> chipList = new ParameterizedTypeReference<List<Chip>>() {};
public Mono<List<ChipDetails>> getChipDetails() {
return webClient.get().uri("chips").retrieve().bodyToMono(chipList).flatMap(chips -> {
return Mono.zip(chips.stream().map(chip -> webClient.get().uri("chipDetails?id="+chip.getId()).retrieve().bodyToMono(ChipDetails.class)).collect(Collectors.toList()), details -> {
List<ChipDetails> chipDetails = new ArrayList<>();
for (Object o : details) {
chipDetails.add((ChipDetails) o);
}
return chipDetails;
});
});
}
这使用 Mono.zip
从列表中的每个 Chip
条目中创建一种批处理请求,同时执行它们。 Flux
最终可能会或多或少地做同样的事情,但并非如此。
如果你只是制作你需要的端点,那么:
ParameterizedTypeReference<List<ChipDetails>> detailsList = new ParameterizedTypeReference<List<ChipDetails>>() {};
public Mono<List<ChipDetails>> getChipDetailsReal() {
return webClient.post().uri("chipDetails").body(webClient.get().uri("chips").retrieve().bodyToMono(chipList), chipList).retrieve().bodyToMono(detailsList);
}
这种方法避免了对同一端点的重复调用,并且正在做您想做的事情。
当您真正指的是 Flux
时,我不喜欢使用 List
。 Flux
是一种具有背压和复杂功能的流媒体,而 List 只是一个 List。