写在前面
您好,我是码农飞哥,感谢您阅读此文。作为一名Java开发者,我们怎么都绕不开调用外部接口的场景,调用的方式要么是通过Http协议来调用,要么是通过RPC协议来调用,通过Http协议调用的话我们就需要用到Http的Api。比较常用的有Apache的HttpClient和原生的HttpURLConnection。这些Api都比较好用,但是我们今天要介绍一种更加好用API,Spring自带的RestTemplate,能力更强,使用更方便。
目录
写在前面
怎么用?
SpringBoot项目
设置超时时间
GET请求
返回业务对象类getForObject方法
POST 请求
postForLocation
exchange 方法的使用
总结
怎么用?
SpringBoot项目
SpringBoot项目中,只需要引入spring-boot-starter-web依赖就可以了,其实spring-boot-starter-web依赖也是SpringBoot项目必备的一个依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
设置超时时间
引入依赖之后,就来开始使用吧,任何一个Http的Api我们都可以设置请求的连接超时时间,请求超时时间,如果不设置的话,就可能会导致连接得不到释放,造成内存溢出。这个是我们需要重点注意的点,下面就来看看RestTemplate如何来设置超时时间呢?我们可以在SimpleClientHttpRequestFactory类中设置这两个时间,然后将factory传给RestTemplate实例,设置如下:
@Configuration
public class RestTemplateConfig {
/**
* 服务器返回数据(response)的时间
/
private static final Integer READ_TIME_OUT = 6000;
/*
* 连接上服务器(握手成功)的时间
*/
private static final Integer CONNECT_TIME_OUT = 6000;
@Bean
public RestTemplate restTemplate(){
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
return new RestTemplate(requestFactory);
}
@Bean
public HttpClient httpClient(){
//默认证书有效
SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
SSLContext sslContext = null;
try {
//信任所有的SSL证书
sslContext = SSLContextBuilder.create().setProtocol(SSLConnectionSocketFactory.SSL)
.loadTrustMaterial((x, y) -> true).build();
} catch (Exception e) {
e.printStackTrace();
}
if (sslContext != null) {
sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
}
// 支持HTTP、HTTPS
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(100);
connectionManager.setValidateAfterInactivity(2000);
RequestConfig requestConfig = RequestConfig.custom()
// 服务器返回数据(response)的时间,超时抛出read timeout
.setSocketTimeout(READ_TIME_OUT)
// 连接上服务器(握手成功)的时间,超时抛出connect timeout
.setConnectTimeout(CONNECT_TIME_OUT)
// 从连接池中获取连接的超时时间,超时抛出ConnectionPoolTimeoutException
.setConnectionRequestTimeout(1000)
.build();
return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();
}
}
说完了RestTemplate的相关设置,下面就来看看平时我们用的最多两种请求方法:get方法和post方法吧。
GET请求
RestTemplate中提供的get请求的方法主要分为两类,一类是只返回请求体,一类是返回ResponseEntity对象,这个对象主要是包装了Http请求的响应状态status,响应头headers,和响应体body。后面我们会详细介绍。首先来看看getForObject方法。
返回业务对象类getForObject方法
getForObject方法的重载方法有如下三个:
/**
方法一,直接将参数添加到url上面。
* Retrieve a representation by doing a GET on the specified URL.
* The response (if any) is converted and returned.
*
URI Template variables are expanded using the given URI variables, if any.
* @param url the URL 请求地址
* @param responseType the type of the return value 响应体的类型
* @param uriVariables the variables to expand the template 传入的参数
* @return the converted object
/
@Nullable
T getForObject(String url, Class responseType, Object… uriVariables) throws RestClientException;
/*
方法二,通过Map来提交参数。
* Retrieve a representation by doing a GET on the URI template.
* The response (if any) is converted and returned.
*
URI Template variables are expanded using the given map.
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the map containing variables for the URI template
* @return the converted object
*/
@Nullable
T getForObject(String url, Class responseType, Map<String, ?> uriVariables) throws RestClientException;
/**
方法三,用URI来请求。
* Retrieve a representation by doing a GET on the URL .
* The response (if any) is converted and returned.
* @param url the URL
* @param responseType the type of the return value
* @return the converted object
*/
@Nullable
<T> T getForObject(URI url, Class<T> responseType) throws RestClientException;
下面定义了一个接口,用来测试上面三个方法的使用,这个接口有两个参数,分别是userId和userName。
根据传入的userId和userName来查询用户,如果可以查询的到的话,则返回查询到的用户,如果查询不到的话,则返回找不到数据。
响应体是JSON格式的。
/**
* get请求获取用户
*
* @param userName 用户名
* @param userId 用户id
* @return
*/
@ResponseBody
@RequestMapping(value = “/getUser.do”)
public ResultData getUserByName(
@RequestParam(name = “userId”,required = false) Integer userId,
@RequestParam(name = “userName”,required = false) String userName) {
if (StringUtils.isAnyBlank(userName)) {
return new ResultData<>(HttpStatus.BAD_REQUEST.value(), null, “参数不能为空”);
}
List userList = new ArrayList<>();
for (int i = 1; i <= 2; i++) {
User user = new User();
user.setUserId(i);
user.setUserName(“张三” + i);
user.setAge(20 + i);
userList.add(user);
}
for (User user : userList) {
if (userName.equals(user.getUserName()) && userId.equals(user.getUserId())) {
return new ResultData(HttpStatus.OK.value(), user, “成功”);
}
}
return new ResultData<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), null, “找不到数据”);
}
下面我们就分别用那三个方法请求/getUser.do接口进行测试:
@Test
public void getForObjectTest() {
String baseUrl = “http://localhost:8081/testRestTemplateApp/getUser.do”;
//方法一: 直接拼接参数,推荐使用
String url =baseUrl+"?userName=张三1&userId=1";
ResultData resultData = restTemplate.getForObject(url, ResultData.class);
System.out.println("*****GET直接拼接参数查询返回结果={}" + JSON.toJSONString(resultData));
//方法一:传参替换,推荐使用
url = baseUrl+"?userName={?}&userId={?}";
resultData = restTemplate.getForObject(url, ResultData.class, “张三2”,2);
System.out.println("*****GET传参替换查询返回结果={}" + JSON.toJSONString(resultData));
//方法一:传参替换,使用String.format,推荐使用
url = baseUrl + String.format("?userName=%s&userId=%s", “张三2”,2);
resultData = restTemplate.getForObject(url, ResultData.class);
System.out.println("******GET使用String.format查询返回结果={}" + JSON.toJSONString(resultData));
//方法二:使用Map,不推荐使用
url = baseUrl + “?userName={userName}&userId={userId}”;
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(“userName”, “张三1”);
paramMap.put(“userId”,1);
resultData = restTemplate.getForObject(url, ResultData.class, paramMap);
System.out.println("******GET使用Map查询返回结果={}" + JSON.toJSONString(resultData));
//方法三:使用URI,不推荐使用
URI uri = URI.create(baseUrl+"?userName=%E5%BC%A0%E4%B8%891&userId=1");
ResultData resultData1 = restTemplate.getForObject(uri, ResultData.class);
System.out.println("******GET使用URI查询返回结果={}" + JSON.toJSONString(resultData1));
}
运行结果如下:
需要注意的是:
。。。。。。。。。。。。。。。。。
版权原因,完整文章,请参考如下: