发生错误后用SpringWebFlux解析json

vof42yt1  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(435)

我正在从rest api接收json,如下所示:

{
    "items": [
        {
            "id": 60659,
            "name": "Display",
            "active": true,
            "account_id": 235
        },
        {
            "id": 36397,
            "name": " Mail Display",
            "active": true,
            "account_id": 107
        }
    ]
}

我用这个方法来解析它:

Mono<List<Item>> getItems(String token) {
        return webCLient
                .get()
                .headers(httpHeaders -> httpHeaders.setBearerAuth(token))
                .retrieve()
                .bodyToMono(ItemResponse.class)
                .map(ItemResponse::getResponse)
                .retryBackoff(RetrySettings.RETRIES, RetrySettings.FIRST_BACKOFF, RetrySettings.MAX_BACKOFF)
                .doOnError(e -> log.error("error: " + e.getCause().toString()))

答复:

public class ItemResponse {

    @JsonProperty("items")
    private List<Item> response;
}

但有时第三方api会返回不同的响应,而不返回顶层 items 属性,看起来像:

[
        {
            "id": 60659,
            "name": "Display",
            "active": true,
            "account_id": 235
        },
        {
            "id": 36397,
            "name": " Mail Display",
            "active": true,
            "account_id": 107
        }
]

此时我的应用程序正在崩溃 JSON decoding error . 我在这个案子里用过:

bodyToMono(new ParameterizedTypeReference<List<Item>>() {})

但我不能总是重构这部分代码来处理它们的json。如何用spring-webflux动态地实现它?就像 try -> parse#1 -> catch -> parse#2 . 所以我需要用方式1解析json,如果出现错误,应用程序应该尝试用方式2解析它。

eqfvzcg8

eqfvzcg81#

您可以将响应作为字符串获取 .bodyToMono(String.class) 做你想做的任何事,多个尝试捕捉。。。但我认为你最好的办法是创造一个自定义的 Deserializer 把它和你的 WebClient 通过 ExchangeStrategies 就像这里描述的:如何定制springwebflux webclient json反序列化。

class MyResponse {

    List<Object> data;

    MyResponse(List<Object> data) {
        this.data = data;
    }
}

class MyResponseDeserializer extends JsonDeserializer<MyResponse> {

    @Override
    public MyResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);

        List<Object> data = new ArrayList<>();

        if (treeNode.isArray()) {
            // parse it as array
        } else {
            // parse it as object and put inside list
        }

        MyResponse myResponse = new MyResponse(data);

        return myResponse;
    }
}

然后

WebClient getWebClient() {
    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addDeserializer(MyResponse.class, new MyResponseDeserializer());

    objectMapper.registerModule(simpleModule);

    ExchangeStrategies strategies = ExchangeStrategies
            .builder()
            .codecs(clientDefaultCodecsConfigurer -> {
                clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
                clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
            }).build();

    return WebClient.builder().exchangeStrategies(strategies).build();
}

Mono<List<Item>> getItems(String token) {
        return getWebClient()
                .get()
                .headers(httpHeaders -> httpHeaders.setBearerAuth(token))
                .retrieve()
                .bodyToMono(MyResponse.class)
                .map(MyResponse::data)
                .retryBackoff(RetrySettings.RETRIES, RetrySettings.FIRST_BACKOFF, RetrySettings.MAX_BACKOFF)
                .doOnError(e -> log.error("error: " + e.getCause().toString()))
}

其余部分与示例中的相同,只是更改类名并添加适当的字段。当然,这只是一个快速编写的演示和一切硬编码,在一个方法,最好有他们注入

相关问题