在开发项目中,不可避免的需要调用某些第三方接口,我们可以使用Apache的HttpClient
请求框架。封装了常用的http的请求头,参数,内容体,响应等等。当然也可以使用HttpURLConnection
Java标准类,来完成一些第三方调用服务。
RestTemplate是Spring提供的同步请求Rest服务的客户端,简化了http服务的通信,支持RestFul原则。
查阅RestTemplate文档,RestTemplate是同步客户端执行HTTP请求,在基础
HTTP客户端库(如JDK HttpURLConnection,Apache HttpComponents等)上公开简单的模板方法API 。
官方文档:
https://docs.spring.io/spring-framework/docs/5.2.8.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
如何使用RestTemplate?(以下案例是基于SpringBoot开发)
1.在使用RestTemplate之前,我们需要对RestTemplate做一些初始化配置。
在构建RestTemplate我们可以通过ClientHttpRequestFactory指定使用不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了两种实现方式:
1.SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层
的Http请求连接,RestTemplate默认是使用SimpleClientHttpRequestFactory,内部是调用jdk的
HttpConnection,默认超时为-1;
2.HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,
使用HttpClient可以配置连接池和证书等信息。
1.SimpleClientHttpRequestFactory构建
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000); //请求超时时间
factory.setConnectTimeout(5000);//连接超时时间
//...
return factory;
}
}
2.HttpComponentsClientHttpRequestFactory 构建
依赖HttpClient包需要引入。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory HttpComponentsClientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
return factory;
}
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
//设置整个连接池最大连接数 根据自己的场景决定
connectionManager.setMaxTotal(100);
//路由是对maxTotal的细分
connectionManager.setDefaultMaxPerRoute(100);
RequestConfig requestConfig = RequestConfig.custom()
//服务器返回数据(response)的时间,超过该时间抛出read timeout
.setSocketTimeout(10000)
//连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
.setConnectTimeout(5000)
//从连接池中获取连接的超时时间,超过该时间未拿到可用连接,
// 会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.setConnectionRequestTimeout(1000)
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}
初始化配置RestTemplate完成后,下文会根据案例来说明如何具体使用RestTemplate。
Get请求案例
服务器端
@RestController
@RequestMapping("/api/rest")
public class TestRestTemplateController {
@GetMapping("/get1/{id}/{name}")
public JSONObject onGet1(@PathVariable("id") Integer id, @PathVariable("name") String name) {
JSONObject object = new JSONObject();
object.put("id", id);
object.put("name", name);
object.put("type", "get2");
return ResultTool.successData(object);
}
@GetMapping("/get2")
public JSONObject onGet2(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name) {
JSONObject object = new JSONObject();
object.put("id", id);
object.put("name", name);
object.put("type", "get2");
return ResultTool.successData(object);
}
}
Get请求之getForObject。以JSON形式自动化转换responseType指定返回类型。
url:请求地址
responseType:返回值类型 结果转换后的对象
uriVariables:携带参数
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables){}
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
public <T> T getForObject(URI url, Class<T> responseType)
@Test
void get1() {
String results = restTemplate.getForObject(BASE_URL + "/get1/1/张三", String.class);
logger.info(results);
输出:{"msg":"","code":200,"data":{"name":"张三","id":1,"type":"get2"}}
}
@Test
void get2() {
JSONObject results = restTemplate.getForObject(BASE_URL + "/get1/{1}/{2}", JSONObject.class, "10086", "我的团长我的团");
logger.info(results.getString("code"));
logger.info(results.getString("data"));
logger.info(results.getString("msg"));
输出:...
}
@Test
void get3() {
Map<String, String> map = new HashMap();
map.put("id", "10001");
map.put("name", "厉兵秣马");
JSONObject results = restTemplate.getForObject(BASE_URL + "/get2?id={id}&name={name}", JSONObject.class, map);
logger.info(results.getString("code"));
logger.info(results.getString("data"));
logger.info(results.getString("msg"));
输出:...
}
Get请求之getForEntity。getForEntity()方法返回的是ResponseEntity对象,ResponseEntity对象
方便处理原生的response信息。
url:请求地址
responseType:返回值类型 结果转换后的对象
uriVariables:携带参数
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables){}
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables){}
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType){}
@Test
void get1() {
ResponseEntity<String> responseEntity = restTemplate.getForEntity(BASE_URL + "/get1/1/张三", String.class);
logger.info(responseEntity.getStatusCode().toString());
logger.info(responseEntity.getStatusCodeValue()+"");
logger.info(responseEntity.getBody());
responseEntity.getHeaders().forEach((v,k)->{
logger.info("headerKey: "+v+"====="+"headerValue: "+k);
});
}
@Test
void get2() {
ResponseEntity<JSONObject> responseEntity = restTemplate.getForEntity(BASE_URL + "/get1/{1}/{2}", JSONObject.class, "10086", "我的团长我的团");
JSONObject results = responseEntity.getBody();
logger.info(results.getString("code"));
logger.info(results.getString("data"));
logger.info(results.getString("msg"));
}
@Test
void get3() {
Map<String, String> map = new HashMap();
map.put("id", "10001");
map.put("name", "厉兵秣马");
ResponseEntity<JSONObject> responseEntity = restTemplate.getForEntity(BASE_URL + "/get2?id={id}&name={name}", JSONObject.class, map);
JSONObject results = responseEntity.getBody();
logger.info(results.getString("code"));
logger.info(results.getString("data"));
logger.info(results.getString("msg"));
}
Post请求案例
@RestController
@RequestMapping("/api/rest")
public class TestRestTemplateController {
//JSON
@PostMapping("/post1")
public JSONObject onPost1(@RequestBody Test test) {
return ResultTool.successData(test);
}
//form-data
@PostMapping("/post2/form/data")
public JSONObject onPost2(@RequestParam("id") Integer id,@RequestParam("name") String name) {
JSONObject object = new JSONObject();
object.put("id", id);
object.put("name", name);
object.put("type", "post2");
return ResultTool.successData(object);
}
}
POST之postForObject。
url:请求地址
request参数可以是aHttpEntity以便向请求中添加其他HTTP标头。
responseType:返回值类型 结果转换后的对象
uriVariables:动态URL
public <T> postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables)
public <T> postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables)
public <T> postForObject(URI url, @Nullable Object request, Class<T> responseType, responseType)
@Test
void get1() {
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//body参数
Map<String, String> map = new HashMap<>();
map.put("id", "1");
map.put("name", "动次打次打次打");
HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(map, headers);
String result = restTemplate.postForObject(BASE_URL + "/post1", httpEntity, String.class);
logger.info(result);
}
@Test
void get2() {
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//body参数
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "2");
map.add("name", "红中红中");
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(map, headers);
///{1}/{2}动态拼接请求地址
JSONObject result = restTemplate.postForObject(BASE_URL + "/post2/{1}/{2}", httpEntity, JSONObject.class, "form", "data");
logger.info(result.toJSONString());
}
@Test
void get3() {
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//body参数
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "3");
map.add("name", "多热热水");
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(map, headers);
//{one}/{two}动态拼接请求地址
Map<String,String> mapUrl = new HashMap<>();
mapUrl.put("one","form");
mapUrl.put("two","data");
JSONObject result = restTemplate.postForObject(BASE_URL + "/post2/{one}/{two}", httpEntity, JSONObject.class, mapUrl);
logger.info(result.toJSONString());
}
POST之postForEntity。
url:请求地址
request参数可以是aHttpEntity以便向请求中添加其他HTTP标头。
responseType:返回值类型 结果转换后的对象
uriVariables:动态URL
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,Class<T> responseType, Object... uriVariables)
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,Class<T> responseType, Map<String, ?> uriVariables)
public <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType)
案例省略...
exchange自定义请求方式
exchange()可以指定HttpMethod,请求体requestEntity。
@Test
void get1() {
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//body参数
Map<String, String> map = new HashMap<>();
map.put("id", "1");
map.put("name", "动次打次打次打");
HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(map, headers);
//exchange 自定义
ResponseEntity<String> result = restTemplate.exchange(BASE_URL + "/post1", HttpMethod.POST, httpEntity, String.class);
logger.info(result.getBody());
}