spring webflux webclient响应将字符串列表转换为字符串

时间:2019-06-15 04:36:28

标签: spring spring-boot java-8 mono spring-webflux

响应:

[ 
 {
  "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();

2 个答案:

答案 0 :(得分:0)

请使用现成的解决方案。您不应该使用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)

答案 1 :(得分:0)

第一个问题是您使用的API不是返回单个对象,而是返回由方括号([])表示的对象数组。

这意味着您至少应该重构代码以使用bodyToFlux()代替bodyToMono()

client
    .get()
    .retrieve()
    // bodyToFlux() in stead of bodyToMono()
    .bodyToFlux(Map.class)
    // ...

第二个问题是,在这种情况下使用Map并不容易,因为您将不得不始终强制转换所有内容,因为您无法传递任何泛型。与适当的班级一起工作会使事情变得简单。例如,您可以编写以下类:

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(),这将不起作用。反应式编程的关键方面之一是一切异步发生。这意味着,如果您尝试对主线程中的数据执行任何操作,则不会发生任何事情。

此外,MonoFlux之类的发布商的另一个功能是懒惰。没有正确的订阅,什至什么都不会发生。

解决方案是正确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()运算符。但是,您不应这样做。如果您使用的是block()运算符,则意味着您根本对使用反应式流不感兴趣,因此您应该问自己,在这种情况下,使用WebClient是否是一个好的解决方案。

出于演示目的,您可以这样编写代码:

String sites = client
    .get()
    .retrieve()
    .bodyToFlux(VersionContent.class)
    .map(VersionContent::getContent)
    .flatMap(Flux::fromIterable)
    .reduce((sites, site) -> sites + "|" + site)
    // You can use this, but you shouldn't
    .block();