RestTemplate
项目中经常会用到 HTTP 请求, 以前都是自己封装的HttpClient,这样其实很浪费效率,最近发现有一个很好用的
东西 RestTemplate,它主要是用来访问 Rest 接口,并且支持传参和接收都用实体类,里面有封装HTTP连接池,
用它可以提高效率,Spring 4.3 及以上版本提供,需要在pom.xml中导入以下包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
SpringBoot 中使用 RestTemplate
RestTemplate自己定义的接口使用起来还是有一点麻烦,我们需要自己封装一个 RestBaseTemplate:
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequestFactory;
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.MappingJackson2HttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class RestBaseTemplate extends RestTemplate {
public RestBaseTemplate() {
super();
}
public RestBaseTemplate(ClientHttpRequestFactory factory) {
super(factory);
}
/**
* 通用请求接口
*
* @param url 请求 URL
* @param params 请求参数
* @param responseType 返回类型
* @param method 请求方式,使用 HttpMethod,默认为 HttpMethod.POST
* @return 响应的 body 内容
*/
public <T> T restTemplate(String url, Map<String, Object> params, Class<T> responseType, HttpMethod method) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null) {
map.setAll(params);
}
switch (method) {
case POST:
return this.postForObject(url, map, responseType);
case GET:
String getParams;
if (params == null) {
getParams = url;
} else {
getParams = "?" + map.keySet().stream().map(k -> String.format("%s={%s}", k, k))
.collect(Collectors.joining("&"));
}
return this.getForObject(url + getParams, responseType, params);
default:
return this.postForObject(url, map, responseType);
}
}
/**
* GET 请求,不带参数
* @param url 请求的URL
* @return 响应的 body 内容
*/
public String get(String url) {
return get(url, new HashMap<>(1));
}
/**
* GET 请求,带参数
* @param url 请求的URL
* @param params 请求的参数,不需要做 Encode 处理
* @return 响应的 body 内容
*/
public String get(String url, Map<String, Object> params) {
return restTemplate(url, params, String.class, HttpMethod.GET);
}
/**
* POST 请求,限制返回类型为字符串
* @param url 请求的 URL
* @param params 请求参数
* @return 响应的 body 内容
*/
public String post(String url, Map<String, Object> params) {
return restTemplate(url, params, String.class, HttpMethod.POST);
}
/**
* POST 请求
* @param url 请求的 URL
* @param params 请求参数
* @param responseType 返回的数据格式
* @return 响应的 body 内容
*/
public <T> T post(String url, Map<String, Object> params, Class<T> responseType) {
return restTemplate(url, params, responseType, HttpMethod.POST);
}
}
里面只定义了,我自己目前常使用的几个方法,其他的可以在使用的时候添加,下面是将 RestBaseTemplate 注册到
Spring 容器中:
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* HTTP 封装类
*/
@Configuration
@ConditionalOnClass(value = {RestTemplate.class, HttpClient.class})
public class RestTemplateConfiguration {
@Value("${remote.maxTotalConnect:20}")//连接池的最大连接数默认为20
private int maxTotalConnect;
@Value("${remote.maxConnectPerRoute:200}")//单个主机的最大连接数
private int maxConnectPerRoute;
@Value("${remote.connectTimeout:2000}")//连接超时默认2s
private int connectTimeout;
@Value("${remote.readTimeout:10000}")//读取超时默认30s
private int readTimeout;
//创建HTTP客户端工厂
private ClientHttpRequestFactory createFactory() {
if (this.maxTotalConnect <= 0) {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(this.connectTimeout);
factory.setReadTimeout(this.readTimeout);
return factory;
}
HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(this.maxTotalConnect)
.setMaxConnPerRoute(this.maxConnectPerRoute).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
httpClient);
factory.setConnectTimeout(this.connectTimeout);
factory.setReadTimeout(this.readTimeout);
return factory;
}
/**
* 初始化RestTemplate,并加入spring的Bean工厂,由spring统一管理
*/
@Bean("restBaseTemplate")
public RestBaseTemplate getRestTemplate() {
RestBaseTemplate restBaseTemplate = new RestBaseTemplate(this.createFactory());
List<HttpMessageConverter<?>> converterList = restBaseTemplate.getMessageConverters();
//加入FastJson转换器
converterList.add(new FastJsonHttpMessageConverter());
return restBaseTemplate;
}
}
接下来可以根据不同的运行环境,在application.properties中配置不同的连接池配置,在代码里面直接使
用 @Autowired 引入就可以使用。
@RestController
public class TestHttpApi implements Serializable {
@Autowired
private RestBaseTemplate restBaseTemplate;
@RequestMapping("test")
public void testRestTemplate() {
String result = restBaseTemplate.get("http://www.baidu.com/");
System.out.println(result);
}
}