记RestTemplate对应messageConverters踩的坑

文章讲述了在使用RestTemplate时,如果没有指定contentType,可能会因引入其他jar包(如HuaweiCloudSDK)导致使用XML解析器引发异常。作者建议指定contentType以避免此类问题,或自定义RestTemplateBean以提高扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记RestTemplate对应messageConverters踩的坑

概要

` 提示:restTemplate,messageConverters

概要:
restTemplate当没有指定contentType的时候。 会根据对应的messageConverters 循环比对,拿到对应的解析器。当引入其他包的时候,可能会导致对应解析器出错导致异常。小编此时是因为引入了一个com.huaweicloud.sdk相关的jar包。 对应包中含有
com.fasterxml.jackson.dataformat.xml.XmlMapper 对应类。以至于加载进来了MappingJackson2XmlHttpMessageConverter。
他和MappingJackson2HttpMessageConverter 对应 if (messageConverter instanceof GenericHttpMessageConverter) 为true.
又因其加载顺序在json之前。 没有指定对应contentType的情况下走到了xml。 导致对应的错误异常。 因此通过源码来探寻一番。给大伙儿避避坑

整体架构流程

当restTemplate初始化的时候。会新增加对应默认的解析器。在这里插入图片描述
其中对应有的converter是根据对应包中是否有加载到对应的类来决定。
在这里插入图片描述
其中当restTemplate调用restTemplate.postForEntity等方法的时候。 跟进对应代码可以发现

在这里插入图片描述

``在这里插入图片描述
此刻会把对应加载的messageConverters加载到对应的 Extractor中。 调用对应的execute方法。
当没有指定contentType的时候。

当没有引入对应其他jar包的时候。默认的解析器为下图:
在这里插入图片描述
当引入其他jar包的时候。
在这里插入图片描述
这里第6个位置的数据已经发生了变化。 当调用restTemplate继续发送的时候。没有指定对应contentType。
在这里插入图片描述
对应的write中。 会去addDefaultHeaders.其中
在这里插入图片描述
其中会拿到对应MappingJackson2XmlHttpMessageConverter初始化
对应这个类初始化的时候是
public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, new MediaType(“application”, “xml”),
new MediaType(“text”, “xml”),
new MediaType(“application”, “*+xml”));
Assert.isInstanceOf(XmlMapper.class, objectMapper, “XmlMapper required”);
}
其中会get(0).拿到application/xml塞入对应的contentType。 以及用MappingJackson2XmlHttpMessageConverter进行解析。
List mediaTypes = getSupportedMediaTypes();
return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);
所以会出异常。

如果指定了对应的contentType。 则循环解析器的同时。会canWrite里面对应传递的contentType。其中解析器中是否匹配。

小结

`当使用restTemplate的时候,注意指定对应的contentType.以免引入jar包的时候无感知的被影响。
也可以在项目中自己创建对应的restTemplateBean。提前指定好对应项目中的使用。 不过相对扩展性不太好。

### 使用 RestTemplate 处理 JSON 数据 当使用 `RestTemplate` 进行 HTTP 请求并处理 JSON 数据时,可以依赖 Spring 的自动序列化/反序列化机制来简化操作。对于发送和接收 JSON 数据的任务,通常会涉及到配置 `RestTemplate` 实例以及利用 Jackson 库中的 `ObjectMapper` 来解析或构建 JSON。 #### 配置 RestTemplate 支持 JSON 为了使 `RestTemplate` 能够正确地处理 JSON 格式的请求体与响应体,应当确保其内部的消息转换器包含了能够支持 JSON 类型的数据处理器。这可以通过自定义 `RestTemplate` Bean 并添加相应的消息转换器实现[^3]: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; @Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); messageConverters.add(converter); RestTemplate restTemplate = new RestTemplate(); restTemplate.setMessageConverters(messageConverters); return restTemplate; } } ``` #### 发送 POST 请求携带 JSON 参数 在执行 POST 方法提交 JSON 数据至服务器端口时,除了要指定消费的内容类型外,还需指明期望接收到的媒体类型为 `"application/json"`。这样做的目的是让客户端和服务端都清楚彼此间交换的信息格式[^2]: ```java import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class JsonService { private final RestTemplate restTemplate; public JsonService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } public Map<String, Object> postJsonData(String url, Map<String, String> jsonData) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(jsonData, headers); ResponseEntity<Map<String, Object>> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<Map<String, Object>>() {}); return responseEntity.getBody(); } } ``` 上述代码片段展示了如何通过 `exchange()` 函数发出带有 JSON 主体的 POST 请求,并将返回的结果映射到 Java 中的标准集合结构——即 `Map<String, Object>` 上[^1]。 #### 将 JSON 响应转化为实体对象 如果目标是从 REST API 获取 JSON 形式的回复并将之直接映射成特定类型的 POJO (Plain Old Java Objects),那么可以直接调用诸如 `getForObject()` 或者 `postForObject()` 等便捷的方法,它们允许传入 Class 对象作为参数用于指示预期的目标类型[^4]。 例如,假设有一个名为 `UserResponse.java` 的类用来表示用户信息,则可以从远程资源获取单个用户的详情如下所示: ```java // UserResponse 是一个简单的POJO类,字段对应于API返回的JSON键名 UserResponse user = restTemplate.getForObject("https://api.example.com/user/{id}", UserResponse.class, userId); ``` 同样地,也可以采用更灵活的方式如 `exchange()` 来完成同样的工作,特别是在需要额外控制的情况下(比如设置头信息或者处理复杂的响应状态)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值