实验环境
- JAVA8
- Spring Boot 多模块架构
基础实现
pom.xml
<!-- HttpClient,如果底层需要使用HttpClient实现,则添加如下依赖 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
application.yml
ConnectTimeout, 用来建立连接的时间,如果到了指定的时间,还没建立连接,则报异常。
ReadTiemout, 已经建立连接,并开始读取服务端资源。如果到了指定的时间,没有可能的数据被客户端读取,则报异常。
# 设置读取超时时间,连接超时时间为5s
project:
restTemplate:
# 客户端和服务端连接超时时间 ms
connectTimeout: 5000
# 客户端和服务端读取数据的超时时间 ms
readTimeout: 5000
# 从连接池获取连接的超时时间,不宜过长
connectionRequestTimeout: 200
# 长连接保持时间 s
timeToLive: 30
# shezhi 总连接数
maxTotal: 1000
# 设置同路由的并发数
defaultMaxPerRoute: 1000
# 设置重置次数
retryCount: 3
# 缓冲数据请求,默认为true
bufferRequestBody: false
ProjectRestTemplateConfig.java
RestTemplate配置类,用于RestTemplate类的实例化和配置。
@Configuration
public class RestTemplateConfig {
@Value("${project.restTemplate.readTimeout}")
private int readTimeout;
@Value("${project.restTemplate.connectTimeout}")
private int connectTimeout;
@Value("${project.restTemplate.timeToLive}")
private int timeToLive;
@Value("${project.restTemplate.maxTotal}")
private int maxTotal;
@Value("${project.restTemplate.defaultMaxPerRoute}")
private int defaultMaxPerRoute;
@Value("${project.restTemplate.retryCount}")
private int retryCount;
@Value("${project.restTemplate.connectionRequestTimeout}")
private int connectionRequestTimeout;
@Value("${project.restTemplate.bufferRequestBody}")
private boolean bufferRequestBody;
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
/**
* 底层使用java.net包提供的方式创建Http连接请求
*/
/*@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(readTimeout);
factory.setConnectTimeout(connectTimeout);
return factory;
}*/
/**
* ClientHttpRequestFactory的另一种实现方式
* 底层使用Httpclient连接池的方式创建Http连接请求
* @return
*/
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
// HttpClient连接池,长连接保持30秒
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(timeToLive, TimeUnit.SECONDS);
// 设置总连接数
connectionManager.setMaxTotal(maxTotal);
// 设置同路由的并发数
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
// 设置header
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
headers.add(new BasicHeader("Accept", "*/*"));
// headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
// headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
headers.add(new BasicHeader("Connection", "keep-alive"));
// 创建HttpClient
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultHeaders(headers)
.setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, true))
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
.build();
// 创建HttpComponentsClientHttpRequestFactory实例
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
// 设置客户端和服务端建立连接的超时时间
requestFactory.setConnectTimeout(connectTimeout);
// 设置客户端从服务端读取数据的超时时间
requestFactory.setReadTimeout(readTimeout);
// 设置从连接池获取连接的超时时间,不宜过长
requestFactory.setConnectionRequestTimeout(connectionRequestTimeout);
// 缓冲请求数据,默认为true。通过POST或者PUT大量发送数据时,建议将此更改为false,以免耗尽内存
requestFactory.setBufferRequestBody(bufferRequestBody);
return requestFactory;
}
}
RestTemplateUtils.java
构建发送Http请求的API, 主要分为发送Get请求和Post请求, 并注册为应用程序的服务。
@Service
public class RestTemplateUtils {
@Autowired
private RestTemplate restTemplate;
private static final Logger log = LoggerFactory.getLogger(RestTemplateUtils.class);
/**
* @param url 请求链接
* @param mapParam 请求参数
* @return 如果请求出错则返回null, 请求成功则返回请求结果
*/
public String postForObject(String url, MultiValueMap<String, ?> mapParam) {
String result = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, ?>> request = new HttpEntity<>(mapParam, headers);
try {
result = restTemplate.postForObject(url, request, String.class);
} catch (Exception e)
{
log.error("调用RestTemplateUtils.postForObject Exception, url=" + url + ",param=" + mapParam, e);
}
return result;
}
/**
* @param url 请求链接
* @param mapParam 请求参数
* @return 如果请求出错则返回null, 请求成功则返回请求结果
*/
public String postForEntity(String url, MultiValueMap<String, ?> mapParam) {
String result = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, ?>> request = new HttpEntity<>(mapParam, headers);
try {
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
result = response.getBody();
} catch (Exception e) {
log.error("调用RestTemplateUtils.postForEntity Exception, url=" + url + ",param=" + mapParam, e);
}
return result;
}
/**
* @param url 请求链接
* @param mapParam 请求参数
* @return 如果请求出错则返回null, 请求成功则返回请求结果
*/
public String getForObject(String url, Map<String, ?> mapParam) {
String result = null;
try {
result = restTemplate.getForObject(url, String.class, mapParam);
} catch (Exception e) {
log.error("调用RestTemplateUtils.getForObject Exception, url=" + url + ",param=" + mapParam, e);
}
return result;
}
/**
* @param url 请求链接
* @param mapParam 请求参数
* @return 如果请求出错则返回null, 请求成功则返回请求结果
*/
public String getForEntity(String url, Map<String, ?> mapParam) {
String result = null;
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class, mapParam);
result = response.getBody();
} catch (Exception e) {
log.error("调用RestTemplateUtils.getForObject Exception, url=" + url + ",param=" + mapParam, e);
}
return result;
}
}
UnitTest.java
发送送请求测试。
private static final Logger log = LoggerFactory.getLogger(RestTemplateTest.class);
@Autowired
private RestTemplateUtils restTemplateUtils;
@Test
public void test() {
// 构建请求参数
String accessToken = projectTokenUtils.getAccessTokenFromRedis();
int pageStart = 0;
int pageSize = 10;
MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>(3);
paramMap.add("accessToken", accessToken);
paramMap.add("pageStart", String.valueOf(pageStart));
paramMap.add("pageSize", String.valueOf(pageSize));
// 发送请求
String result = null;
result = restTemplateUtils.postForEntity(ProjectConstants.URL, paramMap);
// 解析返回结果
JSONObject resultObj = JSON.parseObject(result);
Assert.assertNotNull(result);
// "200".equals(code)表示网络请求成功
String code = resultObj.getString("code");
Assert.assertEquals("200", code);
System.out.println(resultObj);
}