spring webflux webclient 响应将字符串列表转换为字符串
spring webflux webclient response convert list of string to string
回复:
[
{
"version": "1.0",
"content": [
"12345",
"67076",
"123462",
"604340",
"1331999",
"1332608",
"1785581",
]
}
]
代码:
Mono<List<String>> mp = webClient.get().uri(accountMgmtURI)
.retrieve()
.bodyToMono(Map.class)
.flatMap(trans-> {
List<String> content= (List<String>) trans.get("content");
System.out.println("content :: "+content);
return Mono.just(content);
});
System.out.println("content :: "+mp.toString());
String sites=mp.toString();
请使用现成的解决方案。你不应该使用 List<String> content= (List<String>) trans.get("content")
。 Java 是强类型语言 - 所以为类型创建 类。 spring 框架与 类 和对象一起工作。
在这种情况下:
public class VersionedDataResponse {
private List<VersionedData> versionedDataList;
}
....
public class VersionedData {
private String version;
private List<String> content;
}
而 spring 将在 bodyToMono(VersionedDataResponse.class)
处进行转换
第一个问题是您使用的 API 不是返回单个对象,而是返回对象数组,由方括号 ([]
) 指示。
这意味着您至少应该重构您的代码以使用 bodyToFlux()
而不是 bodyToMono()
:
client
.get()
.retrieve()
// bodyToFlux() in stead of bodyToMono(
.bodyToFlux(Map.class)
// ...
第二个问题是,在这种情况下使用 Map
并不容易,因为您将不得不一直转换所有内容,因为您无法传递任何泛型。使用适当的 class 会使事情变得更容易。例如,您可以编写以下 class:
public class VersionContent {
private String version;
private List<String> content;
// TODO: Getters + Setters
}
并将您的代码更改为:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// ...
这段代码将检索每个对象的内容,flatMap
这样每个单独的值都会单独发出。
现在,content
数组中的每个项目都将单独发布。这就引出了第三个问题,即您没有连接字符串。
要连接项目,您可以使用 reduce()
运算符:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// reduce() can be used to merge all individual items to a single item
.reduce((sites, site) -> sites + "|" + site)
// ...
最后一个问题是您使用的是 toString()
,这是行不通的。反应式编程的关键方面之一是一切都发生 异步 。这意味着如果您尝试在主线程中对数据执行任何操作,则什么也不会发生。
此外,Mono
和 Flux
等发布商的另一个特点是他们 懒惰 。没有适当的订阅,什么都不会发生。
解决方法是适当subscribe()
获取你的值,例如:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
.subscribe(System.out::println);
对于您的示例,上面的代码会将以下内容打印到控制台:
12345|67076|123462|604390|1331999|1332608|1785581
请注意,这也意味着您要对这些网站执行的每个操作都应该异步完成。
如果不想异步工作,可以像这样使用 block()
运算符:
String sites = client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
.block();
回复:
[
{
"version": "1.0",
"content": [
"12345",
"67076",
"123462",
"604340",
"1331999",
"1332608",
"1785581",
]
}
]
代码:
Mono<List<String>> mp = webClient.get().uri(accountMgmtURI)
.retrieve()
.bodyToMono(Map.class)
.flatMap(trans-> {
List<String> content= (List<String>) trans.get("content");
System.out.println("content :: "+content);
return Mono.just(content);
});
System.out.println("content :: "+mp.toString());
String sites=mp.toString();
请使用现成的解决方案。你不应该使用 List<String> content= (List<String>) trans.get("content")
。 Java 是强类型语言 - 所以为类型创建 类。 spring 框架与 类 和对象一起工作。
在这种情况下:
public class VersionedDataResponse {
private List<VersionedData> versionedDataList;
}
....
public class VersionedData {
private String version;
private List<String> content;
}
而 spring 将在 bodyToMono(VersionedDataResponse.class)
第一个问题是您使用的 API 不是返回单个对象,而是返回对象数组,由方括号 ([]
) 指示。
这意味着您至少应该重构您的代码以使用 bodyToFlux()
而不是 bodyToMono()
:
client
.get()
.retrieve()
// bodyToFlux() in stead of bodyToMono(
.bodyToFlux(Map.class)
// ...
第二个问题是,在这种情况下使用 Map
并不容易,因为您将不得不一直转换所有内容,因为您无法传递任何泛型。使用适当的 class 会使事情变得更容易。例如,您可以编写以下 class:
public class VersionContent {
private String version;
private List<String> content;
// TODO: Getters + Setters
}
并将您的代码更改为:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// ...
这段代码将检索每个对象的内容,flatMap
这样每个单独的值都会单独发出。
现在,content
数组中的每个项目都将单独发布。这就引出了第三个问题,即您没有连接字符串。
要连接项目,您可以使用 reduce()
运算符:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
// reduce() can be used to merge all individual items to a single item
.reduce((sites, site) -> sites + "|" + site)
// ...
最后一个问题是您使用的是 toString()
,这是行不通的。反应式编程的关键方面之一是一切都发生 异步 。这意味着如果您尝试在主线程中对数据执行任何操作,则什么也不会发生。
此外,Mono
和 Flux
等发布商的另一个特点是他们 懒惰 。没有适当的订阅,什么都不会发生。
解决方法是适当subscribe()
获取你的值,例如:
client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
.subscribe(System.out::println);
对于您的示例,上面的代码会将以下内容打印到控制台:
12345|67076|123462|604390|1331999|1332608|1785581
请注意,这也意味着您要对这些网站执行的每个操作都应该异步完成。
如果不想异步工作,可以像这样使用 block()
运算符:
String sites = client
.get()
.retrieve()
.bodyToFlux(VersionContent.class)
.map(VersionContent::getContent)
.flatMap(Flux::fromIterable)
.reduce((sites, site) -> sites + "|" + site)
.block();