问题描述:
spring-web 版本:
spring-web-3.1.2.RELEASE
使用 spring-web 的 RestTemplate 提交xml数据post请求,响应数据中,中文字符问号乱码:
<msg>??????!</msg>
请求代码:
public void testResquestPostXML() throws Exception{
String url = "http://127.0.0.1/yandype/yandype_response.action";
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
// 请求体
HttpEntity<String> formEntity = new HttpEntity<String>(getXmlStr().toString(), headers);
// 执行请求
RestTemplate restTemplate = new RestTemplate()
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
String xmlStr = responseEntity.getBody();
System.out.println("响应报文:\n" + xmlStr);
}
public StringBuffer getXmlStr(){
StringBuffer xmlString = new StringBuffer();
xmlString.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.append("<xml>")
.append("<request>")
.append("<R1>A</R1>")
.append("<R2>B</R2>")
.append("</request>")
.append("<data>")
.append("<D1>1202004071029301212125</D1>")
.append("<D2>1</D2>")
.append("</data>")
.append("</xml>");
return xmlString;
}
产生原因:
查了类似的问题,发现都是说StringHttpMessageConverter() 消息转换器编码问题。设置,编码即可:
public static void setRestTemplateEncode(RestTemplate restTemplate) {
if (null != restTemplate) {
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (int i = 0; i < messageConverters.size(); i++) {
HttpMessageConverter<?> httpMessageConverter = messageConverters.get(i);
if (httpMessageConverter.getClass().equals(StringHttpMessageConverter.class)) {
messageConverters.set(i, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}
}
}
}
不知是当前 spring-web-3.1.2 版本原因,还是其它细节问题。设置上面的代码没有生效。请求响应的数据还是中文乱码问号。
然后,参考了这位兄弟的博客:
https://blog.csdn.net/weixin_33994429/article/details/92278767
在 xml 里面配置下 RestTemplate 试下看:
<!-- 解决 restTemplate 中文乱码 -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.FormHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/x-www-form-urlencoded;charset=UTF-8</value>
<value>multipart/form-data;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
<value>application/xml;charset=UTF-8</value>
</list>
</property>
<property name="partConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<ref bean="stringHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
<value>multipart/form-data;charset=UTF-8</value>
<value>application/xml;charset=UTF-8</value>
</list>
</property>
</bean>
这时,在测试程序中把 new RestTemplate() 注释掉,使用@Autowired RestTemplate restTemplate; 注入 RestTemplate 再测试请求发现响应数据中,中文字符正常了。
根据 xml 配置,我手动配置一个 RestTemplate 注解配置类:
package com.yandype.config;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
/**
*
* 扩展 RestTemplate 支持访问 https,这里使用httpclient的factory
*
* @Configuration 可理解为用spring的时候xml里面的<beans>标签
* @Bean 可理解为用spring的时候xml里面的<bean>标签
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() throws KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
// 忽略掉对服务器端证书的校验(信任所有)
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain,
String authType)throws CertificateException {
return true;
}
}).build();
// SSLConnectionSocketFactory 中设置允许所有主机名称就可以忽略主机名称验证
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
// 自定义 HttpClient 客户端设置配置参数
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf).build();
// requestFactory 可以保证长连接可控制能够建立的连接数还能细粒度的控制到某个 server 的连接数
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
setRestTemplateEncode(restTemplate);
return restTemplate;
}
@SuppressWarnings("unchecked")
public void setRestTemplateEncode(RestTemplate restTemplate) {
if (restTemplate != null){
// <bean class="org.springframework.http.converter.StringHttpMessageConverter">
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
// <list>
List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
// <property name="supportedMediaTypes">
stringConverter.setSupportedMediaTypes(supportedMediaTypes);
// <bean class="org.springframework.http.converter.FormHttpMessageConverter">
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
// <list>
List<MediaType> formSupportedMediaTypes = new ArrayList<MediaType>();
formSupportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
formSupportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
formSupportedMediaTypes.add(MediaType.TEXT_PLAIN);
formSupportedMediaTypes.add(MediaType.APPLICATION_XML);
// <property name="supportedMediaTypes">
formHttpMessageConverter.setSupportedMediaTypes(formSupportedMediaTypes);
// <list>
List<HttpMessageConverter<?>> formPartConverters = new ArrayList<HttpMessageConverter<?>>();
formPartConverters.add(stringConverter);
formPartConverters.add(new ByteArrayHttpMessageConverter());
formPartConverters.add(new ResourceHttpMessageConverter());
formPartConverters.add(new SourceHttpMessageConverter());
formPartConverters.add(new Jaxb2RootElementHttpMessageConverter());
formPartConverters.add(new MappingJacksonHttpMessageConverter());
// <property name="partConverters">
formHttpMessageConverter.setPartConverters(formPartConverters);
// <list>
List<HttpMessageConverter<?>> partConverters = new ArrayList<HttpMessageConverter<?>>();
partConverters.add(formHttpMessageConverter);
partConverters.add(stringConverter);
// <property name="messageConverters">
restTemplate.setMessageConverters(partConverters);
}
}
@Bean
public ObjectMapper objectMapper(){
return new ObjectMapper();
}
}