调用第三方接口,返回中文是乱码,因此需要引入自定义消息转换器。
重新设置StringHttpMessageConverter字符集为UTF-8,解决中文乱码问题
@Bean(name="httpClientTemplate")
@LoadBalanced
public RestTemplate restTemplate() {
List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
if (!CollectionUtils.isEmpty(converterList)) {
HttpMessageConverter<?> converterTarget = null;
for (HttpMessageConverter<?> item : converterList) {
if (item.getClass() == StringHttpMessageConverter.class) {
converterTarget = item;
break;
}
}
if (converterTarget != null) {
converterList.remove(converterTarget);
HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converterList.add(converter);
}
}
}
但是如果同时引入了jackson-dataformat-xml包的时候,你会发现比较坑爹的现象,返回的json变xml了。
为了解决这个问题,需要更换一下优先级,把MappingJackson2XmlHttpMessageConverter放到解析器列表的最后一个。
if (converterList.get(i) instanceof MappingJackson2XmlHttpMessageConverter) {
Collections.swap(converterList, i, converterList.size() - 1);
}
ClientHttpRequestFactory
它是个函数式接口,用于根据URI和HttpMethod创建出一个ClientHttpRequest来发送请求。
// @since 3.0 RestTemplate这个体系都是3.0后才有的
@FunctionalInterface
public interface ClientHttpRequestFactory {
// 返回一个ClientHttpRequest,这样调用其execute()方法就可以发送rest请求了~
ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
}
它的继承树如下:
可以直观的看到,我们可以使用Apache的HttpClient、OkHttp3、Netty4都可,但这些都需要额外导包,默认情况下Spring使用的是java.net.HttpURLConnection。
使用HttpClient
HttpClient可以用于发送HTTP请求,接收HTTP响应。
导包
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
配置
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
public HttpClient httpClient(){
// 生成默认请求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
// 超时时间
requestConfigBuilder.setSocketTimeout(5000);
// 从连接池获取连接的超时时间
requestConfigBuilder.setConnectionRequestTimeout(20000);
// 连接时间
requestConfigBuilder.setConnectTimeout(5000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
// 连接池配置
// 长连接保持30秒
final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
// 总连接数
pollingConnectionManager.setMaxTotal(1000);
// 同路由的并发数
pollingConnectionManager.setDefaultMaxPerRoute(512);
// httpclient 配置
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(pollingConnectionManager);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
HttpClient client = httpClientBuilder.build();
// 启动定时器,定时回收过期的连接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
pollingConnectionManager.closeExpiredConnections();
pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
return client;
}